java的第二部分 面向对象————多态
4.1面向对象的第三个特征:
多态定义:
多态可以理解为某一类事物的多种存在形态。
例如: 人 可以分为 男人 女人
动物 猫 狗 等
粮食 大米 小麦等
举例
例:动物中猫,狗。
猫这个对象对应的类型是猫类型
猫 x = new 猫();
同时猫也是动物中的一种,也可以把猫称为动物。
动物 y = new 猫();
动物是猫和狗具体事物中抽取出来的父类型。
父类型引用指向了子类对象。
从四个方面对多态进行学习:
1)多态的体现
父类的引用指向了自己的子类对象。 // Anmial a = new Cat();
或者称作是 父类的引用接收自己的子类对象。
abstract class Anmial {
public abstract void eat();
}
class Cat extends Anmial
{
public void eat() {
System.out.println("吃鱼");
}
public void catchMouse() {
System.out.println("逮老鼠");
}
}
public class DuoTaiDemo {
public static void main(String[] args)
{
// Anmial c = new Cat();
//c.eat();
funcation(new Cat());
}
public static void funcation(Anmial a)
{
a.eat();
}
}
2)多态的前提
(类与类之间要有关系)
1、需要存在继承或者实现关系
2、要有覆盖操作
3)多态的好处
多态的存在提高了程序的扩展性和后期可维护性。
4)多态的弊端:
提高了扩展性,但是只能使用父类的引用访问父类中的成员。
5)多态的应用
多态 - 转型
类型的提升:
引用数据类型 (类类型)
Animal a = new Cat (); 类型提升 也称为向上转型(转成父类型)
如果想调用猫的特有方法时怎么办呢?
强制将父类的引用转成子类类型。
Cat c= (Cat)a;
4.1.2多态中成员的特点:
成员函数:
多态中非静态成员函数的特点:编译时:要查看引用型变量所属的类中是否有所调用的方法。如果没有,编译会失败。
编译看左边,运行看右边。
在运行时: 要查看对象所属的类中是否有所调用的成员。(若是子类中也有该方法那么就会将父类中的方法覆盖掉)
class Fu6 {
public void method1() {
System.out.println("Fu method1");
}
public void method2() {
System.out.println("Fu method2");
}
}
class Zi6 extends Fu6
{
public void method1() {
System.out.println("zi method1");
}
public void method3() {
System.out.println("zi method3");
}
}
public class DuoTaiDemo2 {
public static void main(String[] args)
{ Fu6 f = new Zi6();
f.method1(); //此时 结果是:zi method1
f.method2(); // 结果是:Fu method2 子类继承了父类的方法。
// f.method3(); //此处编译会失败 原因引用变量所属的类中没有该方法。
}
}
在运行时: 要查看对象所属的类中是否有所调用的成员。(若是子类中也有该方法那么就会将父类中的方法覆盖掉)
Fu6 f = new Zi6(); //父类的引用指向了自己的子类对象 多态
f.method1(); // 结果是: zi method1
多态中成员变量的特点:
无论编译还是运行只看引用变量所属的类。
class Fu6 {
int num =6;
public void method1() {
System.out.println("Fu method1");
}
public void method2() {
System.out.println("Fu method2");
}
}
class Zi6 extends Fu6
{
int num =7;
public void method1() {
System.out.println("zi method1");
}
public void method3() {
System.out.println("zi method3");
}
}
public class DuoTaiDemo2 {
public static void main(String[] args) {
Fu6 f = new Zi6();
System.out.println(f.num); // 结果是 6
Zi6 z = new Zi6();
System.out.println(z.num); // 结果是 7
静态函数被调用时时只参考引用型变量所在的类即可。
4.2 内部类
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
class Outer{
int x = 3;
class Inner
{
int y =6;
void show(){}
}
void funcation(){}
}
访问规则:
内部类可以直接访问外部类中的成员,包括私有成员。
(原因是内部类中持有一个外部类的引用格式是 外部类名.this)
而外部类要访问内部类中的成员必须要建立内部类的对象。
class Outer {
private int x = 0;
int y = 5;
class Inner {
void show()
{
funcation(); //内部类可以直接访问外部成员 包括私有的
System.out.println("内部类" + x);
}
}
void method() {
Inner in = new Inner(); //外部类要访问内部类需要建立内部类对象
in.show();
}
public void funcation() {
System.out.println("外部类" + y);
}
}
public class InnerDemo {
public static void main(String[] args) {
Outer ot = new Outer();
ot.method();
} // 结果是: 外部类5
内部类0
}
内部类的位置:
内部类定义在成员位置上 可以被private static成员修饰符修饰。
被static修饰的内部类只能访问外部类中的静态成员。
class Outer {
private static int x = 0;
static int y = 5;
private static class Inner // private static 成员修饰符修饰
{
int x =3;
void show()
{ int x = 6 ;
funcation(); // 被static修饰的内部类只能访问外部类中的静态成员
System.out.println("内部类" +Outer.this. x); // 被static修饰的内部类只能访问外部类中的静态成员
} // 注意x处啥也不加默认走的是最近的x,6局部的;加上this走的是该类成员处本类对象的引用 3。加上Outer.this走
的是外部的成员变量。
}
void method() {
Inner in = new Inner();
in.show();
}
public static void funcation() {
System.out.println("外部类" + y);
}
}
public class InnerDemo {
public static void main(String[] args) {
Outer ot = new Outer();
ot.method();
}
}
直接访问内部类成员的格式(内部类不能私有和被静态修饰)
Outer.Inner in = new Outer().new Inner();
in.show();
内部类定义在局部位置上:
也可以直接访问外部类中的成员。
同时可以访问所在局部中的局部变量,但必须是被final修饰的。
class Outer {
private static int x = 0;
static int y = 5;
public static void method() {
final int x= 9;
class Inner {
void show(){
funcation();
System.out.println("内部类" +x); // 局部变量处的局部变量必须被final修饰否则编译会失败(以免产生安全隐患)。
}
Inner in = new Inner(); //在此处类的下面创建内部类对象,在类的上面Jvm编译会报错,认为没有类就new对象。
in.show();
}
4.2.1匿名内部类
匿名内部类是内部类的简化写法。(其实也就是没名字的内部类)
(思考匿名内部类没类名的话内部类的对象怎么创建呢?)
其实匿名内部类就是一个匿名子类对象。
**定义匿名内部类的前提是:
内部类必须继承或实现一个外部其他类或者接口。**
创建一个外部其他类的对象(当外部其他类是抽象类是要覆盖其方法的(抽象类不能被直接创建对象))
匿名内部类的格式: new 外部其他类名或者接口(){ 定义子类的内容 (覆盖类 或者接口的代码) }
abstract class AbsDemo
{
abstract void show();
}
class OuterDemo {
private int x = 5;
int y = 3;
void funcation() {
new AbsDemo() ////new Inner().show(); 这部分其实就是匿名内部类对象
{
void show ()
{
method();
System.out.println("show:::"+x);
}
}.show();
}
public void method()
{
System.out.println("外部类" + y);
}
}
public class NIMingDemo {
public static void main(String[] args) {
OuterDemo ot = new OuterDemo();
ot.funcation() ;
}
}
匿名内部类的演化进程就是下面的内部类继承一个外部其他类缩写。
/*class Inner extends AbsDemo
{
public void show() {
method();
System.out.println("show::" + x);
}
*/
记住:其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖,一个带内容的子类对象。
匿名内部类可以用 父类名 引用型变量 = new 父类的子类对象;匿名内部类的多态。
abstract class AbsDemo {
abstract void show();
}
class Outer{
void funcation()
{
//new Inner().show();
AbsDemo a = new AbsDemo()
{
void show ()
{
method();
System.out.println("show:::"+x);
}
void jjK()
{
System.out.println("hahh");
}
}; // 记住此处是个分号 AbsDemo a = new Inner(); 多态
a.show();
//a.jjk(); //此处编译是失败的,多态 父类中没有此方法编译失败。
}
匿名内部类的应用:
interface Inter
{
void mehod();
}
class Test
{ // 补足代码根据下面的语句
public static Inter funcation()
{
return new Inter()
{
public void method()
{
System.out.println("method run");
}
};
}
}
class TestDemo
{
public static void mian(String[] args)
{
Test.funcation().method();
}
}
匿名内部类作为参数传递:
interface Inter
{
void method();
}
public class InnerDemo2 {
public static void main(String[] args)
{
show(new Inter()
{
public void method()
{
System.out.println("method run");
}
}); //直接调用 静态方法 show (主函数是静态的)
}
public static void show (Inter in)
{
in.method();
}
}