面向对象(多态-概述)
多态:
你只要看到父类引用指向子类对象的表现形式,那么它就体现了多态的特点了
对象的多态性。
class 动物
{}
class 猫extends 动物
{}
class 狗extends 动物
{}
猫 x = new 猫();
动物 x = new 猫();//一个对象,两种形态。
猫这类事物即具备者猫的形态,又具备着动物的形态。
这就是对象的多态性。
简单说:就是一个对象对应着不同类型.
多态在代码中的体现:
父类或者接口的引用指向其子类的对象。
面向对象(多态-好处)
举个例子:
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
这里面的前提可以这么去理解就是:父类里面的内容就是前提,后期就是子类里面的内容,但是这个子类里面的内容必须不是子类所特有了,而是父类继承过来的内容
abstract class Animal
{
abstract void eat();
}
class Dog extends Animal
{
void eat()
{
System.out.println("啃骨头");
}
void lookHome()
{
System.out.println("看家");
}
}
class Cat extends Animal
{
void eat()
{
System.out.println("吃鱼");
}
void catchMouse()
{
System.out.println("抓老鼠");
}
}
class Pig extends Animal
{
void eat()
{
System.out.println("饲料");
}
void gongDi()
{
System.out.println("拱地");
}
}
class DuoTaiDemo
{
public static void main(String[] args)
{
// Cat c = new Cat();
// c.eat();
/*
Cat c = new Cat();
// Dog d = new Dog();
// c.eat();
method(c);
// method(d);
// method(new Pig());
*/
method(new Dog());
}
Public static void method(Animal a)
{
A.eat();
}
/*
public static void method(Cat c)
{
c.eat();
}
public static void method(Dog d)
{
}
*/
}
面向对象(多态-弊端&前提)
多态的弊端:
前期定义的内容不能使用(调用)后期子类的特有内容。
多态的前提:
1,必须有关系,继承,实现。
2,要有覆盖。
面向对象(多态-转型
// Cat c = new Cat();
// c.eat();
// c.catchMouse();
Animal a = new Cat(); //自动类型提升,猫对象提升了动物类型。但是特有功能无法s访问。
//作用就是限制对特有功能的访问。
//专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。
// a.eat();
//如果还想用具体动物猫的特有功能。
//你可以将该对象进行向下转型。
// Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法。
// c.eat();
// c.catchMouse();
// 注意:对于转型,自始自终都是子类对象在做着类型的变化。
// Animal a1 = new Dog();
// Cat c1 = (Cat)a1;//ClassCastException
面向对象(多态-转型2)
事例:
/*
毕老师和毕姥爷的故事。
*/
class 毕姥爷
{
void 讲课()
{
System.out.println("管理");
}
void 钓鱼()
{
System.out.println("钓鱼");
}
}
class 毕老师 extends 毕姥爷
{
void 讲课()
{
System.out.println("Java");
}
void 看电影()
{
System.out.println("看电影");
}
}
class DuoTaiDemo2
{
public static void main(String[] args)
{
// 毕老师 x =new 毕老师();
// x.讲课();
// x.看电影();
毕姥爷 x = new 毕老师();
x.讲课();
x.钓鱼();
// 毕老师 y = (毕老师)x;//ClassCastException
// y.看电影();
}
}
重点:
容易出错:
结果为
Java
钓鱼
面向对象(多态-类型判断-instanceof)
public static void method(Animal a)//Animal a = new Dog();
{
a.eat();
if(a instanceof Cat)//instanceof:用于判断对象的具体类型。只能用于引用数据类型判断,这里面的具体类型还可以是接口名称或者是类都是可以的
// //通常在向下转型前用于健壮性的判断。
{
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d = (Dog)a;
d.lookHome();
}
else
{
}
}
面向对象(多态-成员变量)
事例:
多态时,
成员的特点:
1,成员变量。
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考等号的左边。哦了。
作为了解。
class Fu{
intnum = 3;
voidshow()
{
System.out.println("Fushow");
}
}
class zi extends Fu
{
int num = 4;
void show()
{
System.out.println("zi show");
}
}
class DuoTaiDemo3
{
publicstatic void main(String[] args)
{
Fu f = new Zi();
System.out.println(f.num);
结果:3
为什么会是3也
原因分析:我就new一个子类对象吧,一创建就是两个num,创建完过后,子类已经提升为父类型了,你用父类型的引用去找这个num的时候,它会找父的,覆盖只发生在函数上
另外一个情况:当我注释intnum=3的时候也,再执行语句就会报错
F.show();
会打印出什么也是:zi show,因为会存在覆盖
同样把上面的show方法去掉,然后就调用f。Show就会报错,因为父类中没有这个方法吗,所以也会报错
}
}
面向对象(多态-成员函数)
面向对象(多态-静态函数)
/*
多态时,
成员的特点:
1,成员变量。
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有, 编译失败。
运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成 员变量。
简单说:编译和运行都参考等号的左边。哦了。
作为了解。
2,成员函数(非静态)。
编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译 失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
因为成员函数存在覆盖特性。
3,静态函数。
编译时:参考引用型变量所属的类中的是否有调用的静态方法。
运行时:参考引用型变量所属的类中的是否有调用的静态方法。
简单说,编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
*/
class Fu
{
// int num = 3;
void show()
{
System.out.println("fu show");
}
static void method()
{
System.out.println("fu static method");
}
}
class Zi extends Fu
{
// int num = 4;
void show()
{
System.out.println("zi show");
}
static void method()
{
System.out.println("zi static method");
}
}
class DuoTaiDemo3
{
public static void main(String[] args)
{
Fu.method();
Zi.method();
Fu f = new Zi();//
// f.method();
// f.show();
// System.out.println(f.num);
// Zi z = new Zi();
// System.out.println(z.num);
}
}
面向对象(内部类-概述)
面向对象(内部类-修饰符)
/*
内部类访问特点:
1,内部类可以直接访问外部类中的成员。
2,外部类要访问内部类,必须建立内部类的对象。
一般用于类的设计。
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就是还有的事物定义成内部类来描述。
*/
class Outer
{
private static int num = 31;
class Inner// 内部类。
{
void show()
{
System.out.println("show run..."+num);
}
/*static voidfunction()//如果内部类中定义了静态成员,该内部类也必须是静态的。为什么也,因为如果有静态的也是不是随着类的加载而加载,随着类的消失而消失,我们就不需要再创建对象了吧,所以我们直接用外部类。内部类点上就可以了,可是如果你不弄成静态的话也,你这个类是非静态的,它不加载进来的话也,你这个外部类就不能再是外部类。内部类了
{
System.out.println("function run ...."+num);
}
*/
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
class InnerClassDemo
{
public static void main(String[] args)
{
// Outer out = new Outer();
// out.method();
//直接访问外部类中的内部类中的成员。
// Outer.Inner in = newOuter().new Inner();
// in.show();
//如果内部类是静态的。 相当于一个外部类
// Outer.Inner in = newOuter.Inner();
// in.show();
//如果内部类是静态的,成员是静态的。
// Outer.Inner.function();
}
}
面向对象(内部类- 细节)
/*
为什么内部类能直接访问外部类中成员呢?
那是因为内部类持有了外部类的引用。 外部类名.this
*/
class Outer
{
int num = 3;
class Inner
{
int num = 4;
void show()
{
int num = 5;
System.out.println(Outer.this.num);
}
}
void method()
{
new Inner().show();
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
new Outer().method();
}
}
面向对象(内部类-局部内部类)
这里面为什么要加final呢,不就是在局部吗:
/*
内部类可以存放在局部位置上。
内部类在局部位置上只能访问局部中被final修饰的局部变量。
*/
class Outer
{
int num = 3;
Object method()
{
final int x = 9;
class Inner
{
public String toString()
{
return "show ..."+x;
}
}
Object in = new Inner();
return in;//0x0045
// in.show();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
Outer out = new Outer();
Object obj = out.method();
System.out.println(obj);
}
}
上面这句Object obj = out.method();方法一调用是不是返回一个地址,0x0045,赋值给了obj,这个时候 这个method方法运算完了是不是出栈了,方法一出栈x没有了吧,我们这个ox0045这个对象是不是还在也,就是这个Inner()对象,因为我是obj指向了这个Inner()对象的吧,obj所指向的话也是不是意味着这里面的方法都在栈内存中啊,你说要是这种情况的话x就不能访问了
那你如果在method内部内中Inner里面的toString方法去访问变量x就不存在了,所以也访问不到,所以也加final修饰成为常量,你加了常量就解决问题了啊,final修饰完x是一个常量 ,这个常量啊就意味着x在这里面终生为9,是固定值,它不会变化
说明:这其实也是一种规则你只要记住就行了
面向对象(匿名内部类-概述)
/*
匿名内部类。就是内部类的简写格式。
必须有前提:
内部类必须继承或者实现一个外部类或者接口。
匿名内部类:其实就是一个匿名子类对象。
格式:new 父类or接口(){子类内容}
*/
abstract class Demo
{
abstract void show();
}
class Outer
{
int num = 4;
/*
class Inner extends Demo
{
void show()
{
System.out.println("show ..."+num);
}
}
*/
public void method()
{
//new Inner().show();
new Demo()//匿名内部类。
{
void show()
{
System.out.println("show ........"+num);
}
}.show();
}
}
class InnerClassDemo4
{
public static void main(String[] args)
{
new Outer().method();
}
}
面向对象(匿名内部类-应用)
interface Inter
{
void show1();
void show2();
}
class Outer
{
/*
class Inner implements Inter
{
public void show1()
{
}
public void show2()
{
}
}
*/
public void method()
{
// Inner in = new Inner();
// in.show1();
// in.show2();
Inter in = new Inter()
{
public void show1()
{
}
public void show2()
{
}
};
in.show1();
in.show2();
}
}
/*
通常的使用场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递
*/
class InnerClassDemo5
{
class Inner
{
}
public static void main(String[] args)
{
System.out.println("Hello World!");
/*
show(new Inter()
{
public void show1(){}
public void show2(){}
});
*/
// new Inner();
}
public void method()
{
new Inner();
}
public static void show(Inter in)
{
in.show1();
in.show2();
}
}
匿名内部类-细节
分析原因:
主函数是静态的,classInner这个是不是成员啊,这个成员是非静态的吧,静态的不能访问非静态的吧
现在说一个问题哈,一般人都挂
class Outer
{
void method()
{
Object obj = new Object()
{
public void show()
{
System.out.println("show run");
}
};
obj.show();//因为匿名内部类这个子类对象被向上转型为了Object类型。
//这样就不能在使用子类特有的方法了。
}
}
class InnerClassDemo6
{
public static void main(String[] args)
{
new Outer().method();
}
}
面向对象(对象的初始化过程)\
接着上面写
public static void main(String[] args)
{
new Zi();
}
猜猜输出结果
show zii......0
zi construct....9
事例2:
什么时候使用匿名内部类呢?
通常在使用方法是接口类型参数,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
增强阅读性。