多态(重点)
多态 : 事物的多种形态 举例 : 事物 -> 人 多种形态 : 黄种人,白种人,黑人,红种人 举例 : 事物 -> 狗 多种形态 : 拉布拉多,金毛,柯基,柴犬... 举例 : 事物 -> 水 多种形态 : 气态水蒸气,液态水,固态冰
多态的前提条件
1. 必须有继承/实现关系 //必要条件 2. 有方法的重写 //非必要条件 -> 体现 动态绑定 3. 父引用指向子类对象 //必要条件 Fu fu = new Zi(); Animal animal = new Dog(); √ Animal animal = new Cat(); √ Animal animal = new Tiger(); √ Dog dog = new Animal(); X 多态的本质 : Java中引用数据类型子父类之间的类型转换 类型转换: 基本数据类型 : 前提 -> double > float > long > int > short,byte,char 自动提升 : 小类型 --> 大类型 强制转换 : 大类型 --> 小类型 (强制格式) 引用数据类型 : 前提 -> 继承/实现 // 父类.父接口 > 子类 /实现类 向上转型 : 子类型 ---> 父类 向下转型 : 父类型 ---> 子类型
多态场景下的动态绑定问题
public class Demo { public static void main(String[] args) { Dog dog = new Dog(); useAnimal(dog); Cat cat = new Cat(); useAnimal(cat); Tiger tiger = new Tiger(); useAnimal(tiger); } /* 第一次调用时 : Animal animal = new Dog(); -> 狗吃骨头 第二次调用时 : Animal animal = new Cat(); -> 猫吃鱼 第三次调用时 : Animal animal = new Tiger(); -> 老虎吃人 */ public static void useAnimal(Animal animal){ animal.eat(); } } interface Animal{ public abstract void eat(); } class Tiger implements Animal { @Override public void eat() { System.out.println("老虎吃人"); } } class Dog implements Animal { //方法的重写 @Override public void eat() { System.out.println("狗吃骨头"); } public void lookHome(){ System.out.println("狗看家"); } } class Cat implements Animal { @Override public void eat() { System.out.println("猫吃鱼"); } public void catchMouse(){ System.out.println("猫抓老鼠"); } }
多态的弊端
弊端: 父引用不能访问子类的特有成员! 如何解决多态的弊端: 向下转型 -> 本质是 告知父引用它是一个具体的什么对象 格式: 子类型 子对象 = (子类型)(父引用); 傻子才会用多态的方式创建对象!! -> 子类的功能是最多的,父引用看不到子类的特有行为 要创建对象就一定创建子类对象!
多态的转型问题
多态的本质 : Java中引用数据类型子父类之间的类型转换 类型转换: 基本数据类型 : 前提 -> double > float > long > int > short,byte,char 自动提升 : 小类型 --> 大类型 强制转换 : 大类型 --> 小类型 (强制格式) 引用数据类型 : 前提 -> 继承/实现 // 父类.父接口 > 子类 /实现类 向上转型 : 子类型 ---> 父类 向下转型 : 父类型 ---> 子类型
多态的真实使用场景
n + 1种 n : 此父类型有多少个子类型 1 : 此父类型自己 1. 定义方法的时候,把父类型作为方法的形式参数类型,那么启动方法的方式有n + 1种 2. 定义方法的时候,把父类型作为方法的返回值类型,那么返回方法结果的方式有n + 1种 3. 定义容器时,把父类型作为容器的元素类型,那么容器中可以装的元素的类型有n + 1种Q Animal[] animals = new Animal[3];
多态向下转型的弊端
ClassCastException : 类型转换异常 产生的原因 : 把对象转成了不属于对象类型的对象 如何解决: 在转型之前,做一下类型判断 1. instanceof : 判断类型的 格式 : 对象 instanceof 类型 作用 : 判断前面的对象是否是后面的类型 -> 返回boolean类型结果 2. getClass() 和 类的class属性 getClass() 此方法来自于Object -> Java中所有的对象都有这个方法 作用是 获取此对象的字节码对象 每一个类都有一个类属性 叫 class -> 类名.class; 作用是 获取此类的字节码对象 而一个类 只会有一个字节码对象
匿名对象
匿名 : 没有名字 匿名对象 : 没有对象名的对象 -> 匿名对象也是对象,对象能做的它也能做 格式 : new 类名(实参); 匿名对象不可以重复使用! 使用场景 : 如果一个对象只使用一次,那么就可以不用接收直接使用匿名对象
内部类
内部类 : 定义在类内部的类叫内部类
成员内部类(理解)
成员 : 位置关系 -> 类中方法外 成员内部类的格式: public class Outer{ //成员内部类 public class Inner{ } } 成员内部类是属于外部类的对象的!! 成员内部类的访问问题: 1. 在内部类中访问: 内部类中可以无阻碍的访问外部类的成员 同名的成员变量 : 就近原则 优先访问局部 强制访问本类成员 : this.变量名 强制访问本类外部类成员 : Outer.this.变量名 成员方法 优先访问本类的 -> 每一次方法调用的前面默认隐藏 this. 强制访问本类外部类的成员方法 -> Outer.this.方法名(); 2. 在外部类中访问: 无阻碍的访问外部类中的成员 外部类中访问内部类的成员 -> 不能直接访问,必须先创建内部类的对象 3. 在第三方类中访问内部类的成员 : 创建内部类的对象 Outer.Inner inner = new Outer().new Inner();
静态成员内部类(理解)
static : 一般场景下是不可以用来修饰类的,但是当一个类变成另一个类的成员时,就可以被static修饰 -> 这个成员内部类就同时具备了类和成员的特点 格式: public class Outer{ //静态成员内部类 public static class Inner{ } } 静态成员内部类是属于外部类的!! 成员内部类的访问问题: static 静态只能访问静态 1. 把外部类的成员用 static 修饰 2. 在内部类中创建外部类对象,使用外部类对象去点 3. 在外部类中访问静态成员内部类的成员 就创建内部类的对象即可 4. 在第三方类中访问静态成员内部类的成员 : Outer.Inner inner = new Outer.Inner(); 静态成员内部类使用的更多一些!!
成员内部类何时使用 : 当一个类只为另一个类服务时,可以把这个类定义在那个类的内部!!
public class Person{
public class Heart{//心脏
}
}
局部内部类(了解)
局部内部类的使用场景 : 一个类只为一个方法服务,那么就可以把这个类定义在这个方法内! 格式: public class Outer{ public void method(){ //局部内部类 class Inner{ } } } 局部内部类的访问问题: 1. 在局部内部类中访问: 无阻碍的访问内外部类的非同名成员 强制访问外部类的同名成员 : Outer.this.成员 2. 在外部类中其他方法内访问 : 访问不了! 3. 在局部内部类所在的方法内可以访问 : 创建对象 //必须在类定义之后创建内部类对象 4. 在第三方类中访问局部内部类成员 : 访问不了!
匿名内部类(重点)
匿名内部类(重点) : 为了更方便的使用 接口/抽象父类/普通父类的 格式: 父接口/父抽象类/父类 父引用 = new 父接口/父抽象类/父类(){ //不知道类名的 实现类 / 子类 的类主体 }; 匿名内部类的使用场景: 1. 作为方法的实际参数传递 2. 作为方法的返回值进行返回
权限修饰符
权限修饰符 : public > protected > 不写 > private
同一个类中 | 同一个包下,不同的类中 | 不同包下,有继承关系 | 不同包下,没有继承关系 | |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
不写 | √ | √ | ||
private | √ |
public : 当前模块内都可以访问
private: 只能本类中访问