目录
主要内容:
1、继承
2、多态
3、抽象类
4、接口
一、继承:
1.1继承的特点:
1、Java类只支持单继承,不支持多继承。(一个儿子只能有一个爹)
2、Java类支持多层继承
Java中,java.lang.Object类是所有引用类型(数组、jar包和类库中提供的类包括String、用户自定义的类)的超类。
3、继承特点:
如果想使用这个体系的所有功能,用最底层的类创建对象。(最底层的类创建的对象,可以拥有所有父类(包括超类)的全部非私有成员变量和成员方法)
如果想要使用这个体系的公共功能,用最高层的类创建对象。(最高层的类创建的对象,拥有整个继承体系的公共成员变量和成员方法)
1.2继承的注意问题:
1、子类继承父类的时候,只能继承父类所有非私有的成员(成员变量和方法)
2、子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法。
3、不要为了部分功能而去继承。
4、继承体现的是“is a”的关系。
Animal
Cat
Dog
Pig
1.3 this和super:
1、this和super分别代表什么?
this——代表当前对象的引用,谁来调用我,我就代表谁。
super——代表当前对象父类的引用
2、this和super的区别:
调用成员变量:
this.成员变量;既可以调用本类的,也可以调用父类的(非私有)。
super.成员变量:只能调用父类的
调用成员方法:
this.成员方法():调用本类的,也能调用父类的(非私有)
super.成员方法():只能调用父类的。
调用构造方法:
this():子类的构造器。
super():父类的构造器。(this()和super()不能共存)
1.4 继承中构造方法的关系:
子类中所有的构造方法默认都会调用父类的无参构造方法。
为什么?
1、因为子类的会继承父类的数据,可能会使用父类的数据。
2、在子类初始化之前,必须要先完成父类数据的初始化。
3、在默认情况下,每一个构造方法的第一条语句都是super();
1.5 继承中成员变量的关系:
不同名的成员变量,子类对象可以直接访问。
同名的成员变量,要遵循就近原则(如果使用子类对象调用同名成员变量,name调用的是子类的成员变量)
1.6 继承中成员方法的关系:
不同名成员方法,子类对象可以直接方法。
同名的成员方法,要遵循就近原则。
1.7 访问权限:
public>protected>friendly>private
| 当前类 | 同包中的类 | 子类 | 非子类且非同包的类 |
public | 允许 | 允许 | 允许 | 允许 |
protected | 允许 | 允许 | 允许 | 不允许 |
friendly(默认) | 允许 | 允许 | 不允许 | 不允许 |
private | 允许 | 不允许 | 不允许 | 不允许 |
1.8 方法重写:
1、定义:
Override,子类和父类出现了相同的方法(方法名、方法参数列表、返回类型相同)。特例:返回类型可以是子类与父类的关系。
(前提:class SuperMan extends Person) public class Father { public Person getPerson(String name) { Person person = new Person(); person.name = "父类的人"; return person; } } |
public class Child extends Father { public SuperMan getPerson(String name) { SuperMan man = new SuperMan(); man.name = "子类的人"; return man; } } |
2、应用:
当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写父类的方法。这样既沿袭了父类的方法,又定义了子类特有的内容。
3、注意:
(1)父类中私有方法不能被重写。(因为父子类无法访问父类的私有方法)
(2)父类中friendly(默认的)方法不能被重写。
(3)子类重写父类方法时,访问权限不能更低。
public>protected
父类的方法如果要被重写,必须至少应该是protected修饰。
最好保持一致。
(4)父类静态方法,子类也必须通过静态方法进行重写。
严格意义山看,静态方法重写不算是重写,本质上是静态方法的覆盖。
- 子类重写父类方法时,最好保持返回值类型、访问权限、方法名、参数列表一致。
4、重载(Overload)和重写(Override)的区别:
重载:在同一类的内部出现相同的方法名、不同的参数列表的方法。
重写:继承体系中,子类和父类出现相同的方法名、参数列表、返回值类型(父子关系)的方法。
1.9 final关键字:
1、特点:
如果修饰变量,变量就会变成常量,只能被赋值一次。
如果修饰方法,方法不能被重写。
2、final修饰常量初始化的时机:
显示初始化:在声明时直接初始化
在构造对象时初始化:
(1)可以自定义构造器,在构造器中初始化
(2)可以在构造代码块(初始化块)中初始化
(3)可以在静态代码块中初始化,此时该常量必须使用static修饰。
1.10 随堂练习:
public class User { int id; String password; String email;
public User() { }
public User(int id, String password) { this.id = id; this.password = password; this.email = id + "@gameschool.com"; }
public User(int id, String password, String email) { this.id = id; this.password = password; this.email = email; }
public void speak() { System.out.println("id:" + id + ",password:" + password + ",email:" + email); } } |
public class MyTest { public static void main(String[] args) { User user1 = new User(100, "zhang", "526256706@qq.com"); user1.speak();
User user2 = new User(200, "12345"); user2.speak(); } } |
二、多态:
1.1 多态概述:
1、多态:事物存在多种不同的形态。polymorphic
2、多态的前提:
A 要有继承关系
B 要有方法重写
C 要有父类引用指向子类对象
3、案例分析:
public class Animal { String name;
public Animal() { this.name = "神兽"; }
public void eat() { System.out.println("吃东西!"); } } |
public class Dog extends Animal { String name; int age;
public Dog() { this.name = "哮天犬"; }
public void eat() { System.out.println("吃狗粮!"); } } |
public class MyTest { public static void main(String[] args) { Animal dog = new Dog(); // 父类引用指向子类对象 System.out.println(dog.name); } } |
1.2 多态成员访问:
1.2.1 成员变量:
编译时看左边(父类),运行时看左边(父类)。
1.2.2 成员方法:
编译时看左边(父类),运行时看右边(子类);动态绑定。
1.2.3 静态方法:
编译时看左边(父类),运行时看左边(父类)。静态方法与类有关,静态方法的重写本质是不算是重写。
1.3 向上转型和向下转型:
向上转型:父类引用指向子类对象。
Person person = new SuperMan(); // 向上转型:父类引用指向子类对象 System.out.println(person.name); // 体现的是父类的特征 person.bussiness(); // 调用自己(子类)的方法 |
向下转型:父类对象转换成子类对象。
SuperMan superMan = (SuperMan) person; // 向下转型 System.out.println(superMan.name); // 体现出自己(子类SuperMan)的特征 superMan.fly(); |
1.4 多态的利弊分析:
好处:提高代码的扩展性(由多态保证)
父类对象可以当做形参,接收任何子类对象。
public class Animal { public void eat() { System.out.println("吃东西!"); } } |
public class Cat extends Animal { public void eat() { System.out.println("吃鱼!"); }
public void catchMouse() { System.out.println("抓老鼠!"); } } |
public class Dog extends Animal { public void eat() { System.out.println("吃狗粮!"); }
public void lookHome() { System.out.println("看门!"); } } |
public class MyTest { public static void main(String[] args) { // method(new Dog()); method(new Cat()); }
// 父类对象可以当做形参接收任何子类对象 public static void method(Animal animal) { // instanceof-判断前面这个对象是否是后面这个类的一个实例 if (animal instanceof Dog) { // 向下转型 Dog dog = (Dog) animal; dog.eat(); dog.lookHome(); } else if (animal instanceof Cat) { Cat cat = (Cat) animal; cat.eat(); cat.catchMouse(); } } } |
1.5 多态面试题:
1、第一题:代码本身编译有错误
public class Fu { public void show() { System.out.println("Fu show"); } }
class Zi extends Fu { public void show() { System.out.println("Zi show"); }
public void method() { System.out.println("Zi method"); } }
class TestDemo { public static void main(String[] args) { Fu f = new Zi(); // 编译看左边,运行看右边 f.method(); f.show(); } } |
2、第二题:
public class Test2Demo { public static void main(String[] args) { A a = new B(); a.show();
B b = new C(); b.show(); } }
class A { public void show() { show2(); }
public void show2() { System.out.println("我"); } }
class B extends A { public void show2() { System.out.println("爱"); } }
class C extends B { public void show() { super.show(); // 调用B类中的show(),而B中没有show(),只能调用A中的show()方法 }
public void show2() { System.out.println("你"); } }
|
三、抽象类:
3.1 抽象的概念:
抽象类:如果一个类没有足够的信息来描述一个具体的对象,而需要其他的类来支撑它,那么这样的类被称为抽象类。
3.2 抽象类的特点:
1、抽象类和抽象方法必须使用abstract关键字修饰
2、抽象类不一定有抽象方法,有抽象方法的类一定不是具体类,是抽象类或接口。
3、抽象类不能实例化,必须按照多态的方式,由具体的子类实例化
4、抽象类的子类:要么是抽象类,要么是重写抽象类的所有抽象方法的具体类。
public class MyTest { public static void main(String[] args) { Animal cat = new Cat();// 抽象类不能实例化,必须按照多态的方式,由具体的子类实例化。 cat.eat(); } }
abstract class Animal { // 抽象类由abstract关键字修饰 public abstract void eat(); // 抽象方法
public abstract void hobby();// 抽象方法
public void method() { // 具体的方法,抽象类不一定有抽象方法,抽象类中可以有具体的方法 System.out.println("bbbbbb"); } }
// 抽象类的子类如果是具体类,必须要重写抽象类的全部抽象方法。 class Cat extends Animal { public void eat() { System.out.println("吃鱼!"); }
public void hobby() {
} }
// 抽象类的子类可以是抽象类 abstract class Dog extends Animal { public abstract void hobby(); }
class WolfDog extends Dog { public void hobby() {
}
public void eat() {
} } |
3.3 抽象类成员的特点:
1、成员方法:既可以是抽象的,也可以是非抽象的(实例方法)。
抽象方法:强制要求子类必须要做的事情。
非抽象方法:子类可以直接继承,也可以重写,提高代码的复用性。
2、成员变量:既可以是变量,也可以是常量。(不能用abstract修饰)
3、构造方法:抽象类虽然不能实例化,但是有构造方法,用于子类访问父类数据时进行数据初始化。
3.4 面试题:
1、一个类如果没有抽象方法,是否可以被定义为抽象类?
可以的。目的是不让其他类创建本类对象,如果需要创建本类对象,只能交给子类完成。
2、abstract关键字不能与哪些关键字共存?
abstract与static:被abstract修饰的方法是抽象方法,没有方法体;而被static修饰的方法可以直接通过”类.方法名”访问,但是”类.抽象方法”的访问是完全没有意义的。
abstract和final:被abstract修饰的方法强制子类(或者是子类的子类)重写;被final修饰的方法不允许被重写,二者矛盾。
abstract和friendly(缺省)/private:被abstract修饰的方法要强制子类重写、必须要能够让子类访问到;friendly(缺省)/private修饰的方法不能让子类访问,二者矛盾。