抽象类接口和对象继承面试要点
2016-09-19 20:38
218 查看
抽象类
含有抽象(abstract关键字)方法的类即为抽象类。(抽象类可以不含抽象方法,但是这样抽象类本身意义就很小了)抽象类和普通类的区别:
1. 抽象方法必须为public,protected(private不能被继承)
2. 抽象类不能创建对象
3. 如果一个类为抽象类的子类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则子类也必须为抽象类。
接口
Java设计的接口(使用interface关键字)初衷:对行为的抽象。
接口中可以含有方法和变量
a. 接口中的变量:缺省且必须为public static final
b. 接口中的方法:缺省且必须为public abstract
抽象类和接口理解和应用
定义一个Person抽象类
1. 子类Boy
2. 子类Girl
public abstract class Person { private boolean sex; //性别 abstract public void run(); //跑方法 } class Boy extends Person{ @Override public void run() { System.out.println("Boy run"); } public boolean getSex(){ return true; } } class Girl extends Person{ @Override public void run() { System.out.println("Girl run"); } public boolean getSex(){ return false; } }
定义一个Dog抽象类
1. 子类Bomex
2. 子类Shiba
public abstract class Dog { public String type; //狗的种类 abstract public void run(); //跑方法 } class Bomex extends Dog{ public void run() { System.out.println("Bomex run"); } public String getType(){ return "Bomex"; } } class Shiba extends Dog{ public void run() { System.out.println("Shiba run"); } public String getType(){ return "Shiba"; } }
我们注意到:
在属性上,我们把男孩类和女孩类做了一个再抽象形成了Person抽象类。
把博美类和柴犬类做了一个再抽象形成了Dog抽象类。
在方法上,这几个类都拥有run()这个属性。即无论是是人还是小狗都会跑,这样就会存在大量的代码复写。
我们可以这样理解: 抽象类是对类的再抽象,决定一个对象“是不是”。
1. 即小明是不是男孩,男孩是不是人。
2. 我家旺旺是不是博美,博美是不是狗。
接口是对行为,对能力的抽象,决定一个对象"会不会"。
1. 即小明会跑
2. 旺旺也会跑
这样的话,可以建立一个run接口,无论是Person类、还是Dog类都实现该接口,从而实现其中run方法。
将代码重写:
新建一个Run接口,建立抽象方法run()
public interface Run { abstract public void run(); }
Person改写为:
public abstract class Person implements Run{ private boolean sex; //性别 } class Boy extends Person{ @Override public void run() { System.out.println("Boy run"); } public boolean getSex(){ return true; } } class Girl extends Person{ @Override public void run() { System.out.println("Girl run"); } public boolean getSex(){ return false; } }
Dog类改写为:
public abstract class Dog implements Run{ public String type; //狗的种类 } class Bomex extends Dog{ @Override public void run() { System.out.println("Bomex run"); } public String getType(){ return "Bomex"; } } class Shiba extends Dog{ public void run() { System.out.println("Shiba run"); } public String getType(){ return "Shiba"; } }
可以看出来,这样的改写,方便了对行为的管理。
接口和抽象类相同和区别
相同:
1. 接口和抽象类都不能被实例化2. 接口和抽象类都可以包含抽象方法
区别:
在设计目的上: 接口作为系统与外界交互的窗口,体现的是一种规范。
对于设计实现者,接口规定了实现者必须向外提供哪些服务。对于接口的调用者,接口规定了调用者可以调用那些服务。
对于多个程序而且,接口是多个程序之间的通信标准。
抽象类为多个子类的父类,体现的是一种模板式设计。
对于抽象类中的方法,是系统实现过程中的中间产品,这个中间产品需要经过子类的再完善,才能成为最终产品。
在使用上:
接口只能有抽象方法和静态变量
抽象类可以作为普通类使用,只是不能生成对象
类和对象
1. 如果用户没有自定义构造器,则系统会自动创建一个static属性的无参构造器。2. 在实例化一个对象的过程中
a. 首先Java执行引擎会寻找是否已加载这个类,如果未加载,则先加载再生成对象。已加载,则直接生成对象
b. 在类加载的过程中,如果有static变量和static静态代码块,会先加载static属性。(按上下顺序)
c. 在生成类对象过程中,会先初始化类对象的所有成员变量(在程序的任何位置),再执行构造器
构造器完全负责对象的创建?
在实例化一个对象的过程中:
1. 首先系统为该对象分配内存空间,并为对象执行默认的初始化操作。此时对象已经产生了,只是外部还不能使用
2. 再调用构造器方法(注意我们常在构造器内使用this关键字,说明此时对象已经建立),调用完构造器后return出该类的实例化对象
3. 对于this关键字可以简单的理解和super关键字用法类似,this总是指向到调用该方法的对象,而super指向this指向对象的父对象。(java在创建一个子类对象,会隐式的创建该类的父类的对象,this指向子类对象,super指向父类对象,注意在子类构造器中调用父类构造器,使用super关键字需要放在第一句,同理,在一个子类构造器中调用另一个构造器使用this关键字也需要放在第一句)
继承
1. 一个子类只能继承一个父类,一个父类可以有多个子类2. 子类能够访问父类的非pirvate变量和方法
3. 子类和父类之间变量和方法存在隐藏和覆盖的关系
a. 如果子类中出现和父类同名的成员变量,则子类成员变量会屏蔽父类的成员变量(隐藏现象), 如果要调用父类的成员变量,则需要使用super关键字。
b. 如果子类中出现和父类同名的成员方法,则子类成员方法会覆盖父类的成员方法的,使用super调用
c. 如果子类和父类有同名的静态方法,则会产生隐藏现象
(子类和父类同名现象会在多态上体现的更明显)
实际代码应用
对于子类和父类构造器等static等调用顺序1. 我们假设系统没有载入子类和父类,需要实例化一个子类对象
2. 理论上过程应该如下:
a.在加载子类前,会先加载父类,故先考虑父类
1) 先初始化父类里的static变量和方法
2) 初始化父类里的成员变量
3) 调用父类的构造方法
b. 父类加载完毕后,会加载子类,考虑子类
1) 先初始化子类里的static变量和方法
2) 初始化子类里的成员变量
3) 调用子类的构造方法
示例代码
package org.delphi.fan; public class test { public static void main(String[] args) { new Student(); } } class Eat{ public Eat(String person){ System.out.println(person+" eat constructer."); } } class Student extends Person{ Eat eat = new Eat("student"); public Student(){ System.out.println("student constructer."); } static{ System.out.println("student static code."); } } class Person{ Eat eat = new Eat("person"); public Person(){ System.out.println("person constructer."); } static{ System.out.println("person static code."); } }
理论输出为:
person static code. person eat constructer. person constructer. student static code. student eat constructer. student constructer.
实际输出为:
person static code. student static code. person eat constructer. person constructer. student eat constructer. student constructer.
为什么会出现这个结果,是因为JVM的加载过程中,先考虑静态变量(代码块),再考虑继承关系.
对于有static属性的继承关系内,Java创建对象的完整过程为
1. 分配父类静态变量(静态代码块)
2. 分配子类静态变量(静态代码块)
3. 加载父类成员变量 --> 调用父类构造器 (父类对象创建完毕)
4. 加载子类成员变量 --> 调用子类构造器 (子类对象创建完毕)
对于子类和父类隐藏和覆盖的解释
1. 我们假设系统使用子类构造方法实例化一个父类对象,并调用父类和子类中同名的静态方法、成员方法和变量2. 理论上过程应该如下:
1) 调用父类的构造方法
2) 调用子类的构造方法
3) 调用父类对象同名成员属性和静态成员方法时:存在隐藏现象(使用父类属性)
4) 调用父类对象同名方法时:存在覆盖现象(使用父类属性)
示例代码
package org.delphi.fan; public class test { public static void main(String[] args) { Person person = new Student(); System.out.println("name:"+person.name); person.eat(); person.fight(); } } class Student extends Person{ public String name="STUDENT"; public Student(){ System.out.println("student constructer."); } public void eat(){ System.out.println("student eat."); } public static void fight(){ System.out.println("student static fight."); } } class Person{ public String name="PERSON"; public Person(){ System.out.println("person constructer."); } public void eat(){ System.out.println("person eat."); } public static void fight(){ System.out.println("person static fight."); } }
理论输出为:
person constructer. student constructer. name:PERSON student eat. person static fight.
实际输出为:
person constructer. student constructer. name:PERSON student eat. person static fight.
多态
Java引用变量有两个类型:一个是编译时的类型(声明该变量时使用的类型),一个是运行时的类型(实例化赋给该变量的对象类型)。对于向上转型:
1. 引用变量只能调用声明该变量时所用类里包含的方法。2. 引用方法会被子类(实例声明)覆盖,即方法行为总是子类方法行为
3. 而对象的属性则不具备多态性,即保持父类(编译声明)的变量属性
对于向下转型:
保证程序不会报错,使用if(对象 instanceof 类名){//对象必须为子类或者父类的对象 否则返回false
子类名 子对象 = (子类名)父对象 ;
}
对于多态的作用,可以这么理解:
问题:现在我们需要喝水,对此实现方案,是编写一个水类,含有喝水drink方法。
class Water{ public void drink(); }
因为水有很多种,举个例子: 农夫山泉, 并且其有一个特殊的要求,就是喝前需要摇一摇。
实现代码可以为:
class NongFuSQ extends Water{ public void drink(){ yaoyiyao(); //NongFuSQ需要摇一摇 } public void yaoyiyao(){ System.out.println("yaoyiyao!"); } }
此时我们要喝水可以用这样代码实现:
NongFuSQ water = new NongFuSQ(); water.drink();
现在如果换了一种水,例如:哇哈哈和康师傅,他们的喝前需要的操作各自不同
class WaHaHa extends Water{ public void drink(){ addSuger(); //WaHaHa需要加糖操作 } public void addSuger(){ System.out.println("addSuger!"); } } calss KangShiFu extends Water{ public void drink(){ addNode(); //KangShiFu需要和面条一起 } public void addNode(){ System.out.println("addNode!"); } }
此时如果我要喝其他的水,则喝水代码要改成:
//如果是哇哈哈 WaHaHa water = new WaHaHa(); water.drink();
</pre><pre name="code" class="java" style="font-size: 14px; font-weight: bold;">//如果是康师傅 KangShiFu water = new KangShiFu(); water.drink();
只要我一换水, 就需要改写代码,如果我在多处使用water对象,且使用了大量water包含的方法(方法中可能还包括一些子类特有的方法)。
随着代码量的增大,则改动的代码也会更大。不利于代码维护。
而从问题的实际角度来想,我只是想喝水,我不管你给我的是什么水,你的水是什么牌子,是怎么弄过来的。
此时可以用多态这个概念来实现:以后我需要换水的时候,只需要改变water实例化的对象。
Water water = new WaHaHa(); water.drink(); <span> </span>//喝水只需要调用一个water就可以
在这种情况下,water调用的方法都是由Water类管理。[b]water对象只可以调用[b]Water类定义好的方法。[/b][/b]
在这样的情况下,如果我向换一种水喝,只需要实现新的子类,然后更改一下 Water water = new XXXX(); 不用考虑后面的代码是否有异常,也不需要代码功能是否完善(因为只要不是父类有的方法,后面压根就不能调用)。
面向对象三大特征:
封装
1. 隐藏类的实现细节,不允许外部直接访问,便于修改和增加控制逻辑,限制对属性不合理的访问。2. 把方法暴露出来,让方法来操作或访问这些属性。
继承
提高了代码复用,有利于代码的维护。
多态
增加代码的健壮性。==和equals比较运算符
==在比较普通类型 只要值相同即可, 在比较两个引用变量时候,两个引用变量必须指向同一对象equals是Object类中的一个方法,在String类中,可以理解为判断两个引用变量对象的字符串序列是否相同,在其他类中也是判断是否指向同一对象,如果需要做特殊判定,可以重写该方法。
常用的比较可靠的equals代码复写(使用反射机制)
public class Person { private String id; public String getID(){ return id; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } // if (obj!=null && obj.getClass()==Person.class) { Person per = (Person)obj; if (this.getID().equals(per.getID())) { //判断对象ID属性是否相同 return true; } } return false; } }
相关文章推荐
- java面向对象浅析--抽象类、接口与多继承
- 【胡侃Java】类、抽象类、接口、继承和对象
- java类、抽象类、接口、继承和对象解析
- [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类
- java类、抽象类、接口、继承和对象解析
- 接口、类、抽象类、对象,继承的理解
- 基础学习day07---面向对象三---继承,接口与 抽象类
- 黑马程序员_面对对象_继承_抽象类_接口
- 一次性理清java 中的 类、抽象类、接口、继承、对象
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- 黑马程序员_面向对象2_(继承、多态、抽象类abstract、接口interface、内部类)
- 8.python之面相对象part.4(接口继承的思想设计,这种东西也叫抽象类)
- JAVA基础学习(七)---面向对象三---继承,接口与 抽象类
- 2.0 面向对象 类与实例(关键字)、封装、继承、多态(虚方法,抽象类,抽象方法,接口)
- Java类、属性、方法、对象、继承、多态、接口、抽象类...
- java类、抽象类、接口、继承和对象解析
- 黑马程序员_面向对象二(继承,多态,抽象类abstract,接口Interface,内部类)
- Kotlin学习(四)—— 类和对象,继承,覆盖,抽象类,属性和字段,接口,可见性修饰符,扩展
- 黑马程序员——【Java基础】——面向对象(一)概述、类与对象、继承、抽象类、接口、多态、内部类
- Java第4次实验提纲(面向对象2-继承、多态、抽象类与接口与Swing)