JavaSE实战——面向对象(中) 抽象类,接口,多态,内部类,匿名内部类

来源:互联网 发布:mac 远程桌面 linux 编辑:程序博客网 时间:2024/05/18 15:55

抽象类

    描述一个事物,却没有足够信息,这时就将这个事物称为抽象事物。面对抽象的事物,虽然不具体,但是可以简单化,不用面对具体的事物。(这样其实更方便于面对同一类对象)

    抽象类:笼统,模糊,看不懂,不具体!
    抽象类也是不断地向上抽取而来的。但是只抽取了方法声明,并不抽取具体的方法实现。只在乎有哪些功能,具体功能实现内容,由不同子类完成。抽象类中,可以定义抽象内容让子类实现,也可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。
    抽象类的特点:
    1.抽象方法只能定义在抽象类中,抽象类和抽象方法都需要用abstract来修饰。(abstract可以描述类和方法,不可以描述变量)
    2.抽象类中,也可以定义非抽象方法。
    3.抽象方法只定义方法声明,并不定义方法实现。
    4.抽象类不能实例化。不能用new关键字创建对象。
    5.只有子类继承抽象类并覆盖了抽象类中的所有抽象方法后,子类才能具体化(实例化),子类才可以创建对象。否则,该子类还是一个抽象类。(好处:强制抽象类的子类具备并实现所有的抽象方法,才能实例化。)

  1. abstract class 犬科{  
  2.     abstract void 吼叫();  
  3. }  
  4. class 狗 extends 犬科{  
  5.     void 吼叫(){  
  6.         System.out.println("汪汪");  
  7.     }  
  8. }  
  9. class 狼 extends 犬科{  
  10.     void 吼叫(){  
  11.         System.out.println("嗷嗷");  
  12.     }  
  13. }  
  14. class AbstractDemo{  
  15.     public static void main(String[] args){  
  16.           
  17.     }  
  18. }  
    关于抽象类,这里注明几个细节问题:
    1.抽象类中有构造函数吗?
       有。抽象类的构造函数虽然不能给抽象类对象实例化,因为抽象类不能创建对象,
       但是抽象类有子类,它的构造函数可以给子类对象实例化。

    2.抽象类和一般类的异同
       相同点:
             抽象类和一般类都是用来描述事物的,都在内部定义了成员,进行属性和行为的描述。
       不同点;
             a.抽象类描述事物的信息不具体。
                一般类描述事物的信息具体。
             b.一般类中不能定义抽象方法,只能定义非抽象方法。
                抽象类中可定义抽象方法,同时也可以定义非抽象方法。
             c.一般类可以被实例化。
                抽象类不可以被实例化。
    3.抽象类一定是个父类吗?
       是的。因为需要子类覆盖所有抽象方法后,才可以对子类实例化,使用这些方法。
       abstract class Demo extends Fu{}
       class Sub extends Demo{}
    4.抽象类中可以不定义抽象方法吗?
       可以。但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。
       通常这个类中的方法有方法体,但是却没有内容。

  1. abstract class Demo{  
  2.         void show1()  
  3.         {}  
  4.         void show2()  
  5.         {}  
  6.     }  
    5.抽象关键字abstract和哪些关键字不能共存呢?
        final: final修饰类或者方法不可以被继承或覆盖,abstract修饰的类或方法必须有子类或被覆盖。
        private:私有的方法,子类无法访问到,不叫覆盖。(public不能覆盖private。final不能被覆盖。)
        static:静态区中的内容不需要对象,直接类名调用,抽象类名调用抽象方法没有意义。

    需求:公司中程序员有姓名,工号,薪水,工作内容。
              项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
    对给出需求进行数据建模。
    分析:
           程序猿:
                  属性:姓名,工号,薪水
                  行为:工作内容
          项目经理:
                  属性:姓名,工号,薪水,还有奖金
                  行为:工作内容
    两者不存在所属关系,但是有共性内容,可以向上抽取。
    两者的共性类型是什么?雇员。
    雇员:
           属性:姓名,工号,薪水
           行为:工作内容

  1. abstract class Employee{//对于老板而言,面对雇员来指挥做事情,比面对程序猿和经理做事情,简单得多。  
  2.     private String name;  
  3.     private String id;  
  4.     private double pay;  
  5.     Employee(String name, String id, double pay){  
  6.         this.name = name;  
  7.         this.id = id;  
  8.         this.pay = pay;  
  9.     }  
  10.     public abstract void work();  
  11. }  
  12. class Programmer extends Employee{  
  13.     Programmer(String name, String id, double pay){  
  14.         super(name,id,pay);  
  15.     }  
  16.     public void work(){  
  17.         System.out.println("code");  
  18.     }  
  19. }  
  20. class Manager extends Employee{  
  21.     private double bonus;  
  22.     Manager(String name, String id, double pay, double bonus){  
  23.         super(name,id,pay);  
  24.         this.bonus = bonus;  
  25.     }  
  26.     public void work(){  
  27.         System.out.println("manage");  
  28.     }  
  29. }  
  30. class AbstractDemo{  
  31.     public static void main(String[] args){  
  32.         new Manager("lichunchun","SA14010001",200000,5000).work();  
  33.     }  
  34. }  
模板方法设计模式

    解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

  1. abstract class GetTime{  
  2.     public final void getTime(){//此功能如果不需要复写,可加final限定  
  3.         long start = System.currentTimeMillis();  
  4.         code();//不确定的功能部分,提取出来,通过抽象方法实现  
  5.         long end = System.currentTimeMillis();  
  6.         System.out.println("runtime : "+(end - start)+" ms");  
  7.     }  
  8.     public abstract void code();//抽象不确定的功能,让子类复写实现  
  9. }  
  10. class SubDemo extends GetTime{  
  11.     public void code(){//子类复写功能方法  
  12.         for(int x = 0; x < 1000; x++){  
  13.             System.out.println("x");  
  14.         }  
  15.     }  
  16. }  
  17. class TemplateDemo{  
  18.     public static void main(String[] args){  
  19.         new SubDemo().getTime();  
  20.     }  
  21. }  
接口

  1. abstract class AbsDemo{  
  2.         public abstract void show1();  
  3.         public abstract void show2();  
  4. }  
     抽象类中所有的方法都是抽象的。这时,可以把抽象类用另一种形式来表示:接口。初期可以理解为接口是特殊的抽象类。
    定义接口使用的关键字不是class,是interface。
    接口中包含的成员,最常见的有全局常量、抽象方法。
    注意:接口中的成员都有固定的修饰符,即使不写,编译器也会自动补全。

               成员变量:public static final 
               成员方法:public abstract

               共性:成员都是public修饰的。

  1. interface Inter{  
  2.     public static final int NUM = 4;  
  3.     public abstract void show1();  
  4.     public abstract void show2();  
  5. }  
  6. class Demo implements Inter{  
  7.     public void show1(){}  
  8.     public void show2(){}  
  9. }  
  10. class InterfaceDemo{  
  11.     public static void main(String[] args){  
  12.         new Demo();  
  13.     }  
  14. }  
    接口的特点:
    1.接口不可以实例化。因为接口中的方法都是抽象方法。
    2.接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。
    3.接口是用来被实现的。
    类与类之间存在着继承关系,类与接口中间存在的是实现关系。继承用extends,实现用implements。

  1. class Fu1{  
  2. <span style="white-space:pre">    </span>void show(){  
  3.         sop("Fu1 show");  
  4.     }  
  5. }  
  6. class Fu2{  
  7.     void show(){  
  8.         sop("Fu2 show");  
  9.     }  
  10. }  
  11. class Zi extends Fu1,Fu2{  
  12.       
  13. }  
  14. new Zi().show();//调用的不确定性。原因在于方法主体内容不同。  
    Java中不直接支持多继承,而是对该机制进行改良。通过接口来解决问题。将多继承转换成了多实现,在子类具体实现时,子类中才有方法主体,不会出现调用的不确定性。
  1. interface InterA{  
  2.     public abstract void show();  
  3. }  
  4. interface InterB{  
  5.     public abstract void show();  
  6. }  
  7. class SubInter implements InterA,InterB{//多实现  
  8.     public void show(){  
  9.         System.out.println("inter show");  
  10.     }  
  11. }  
  12. class InterfaceDemo2{  
  13.     public static void main(String[] args){  
  14.         SubInter in = new SubInter();  
  15.         in.show();  
  16.     }  
  17. }  
    其实,我们可以形象地将继承和实现比喻为只认一个爹,但可以有很多个叔叔,只不过这里的叔叔没有方法主体。

  1. class Fu{  
  2.     void show(){  
  3.         System.out.println("fu show");  
  4.     }  
  5. }  
  6. interface Inter{  
  7.     public abstract void show1();  
  8. }  
  9. class Zi extends Fu implements Inter{  
  10.     public void method(){  
  11.         System.out.println("zi method");  
  12.     }  
  13.     public void show1(){  
  14.         System.out.println("zi show1");  
  15.     }  
  16. }  
  17. class InterfaceDemo3{  
  18.     public static void main(String[] args){  
  19.         Zi z = new Zi();  
  20.         z.show();  
  21.         z.show1();  
  22.         z.method();  
  23.     }  
  24. }  
     类与类之间:单继承关系。is a,是什么。
    类与接口之间:实现关系。like a,像什么。
    接口与接口之间:多继承关系。
  1. interface Inter1{  
  2.     public abstract void show1();  
  3. }  
  4. interface Inter2{  
  5.     public abstract void show2();  
  6. }  
  7. interface Inter3 extends Inter1,Inter2{  
  8.     public abstract void show3();  
  9. }  
  10. class Inter implements Inter3{  
  11.     public void show1(){}  
  12.     public void show2(){}  
  13.     public void show3(){}  
  14. }  
    为了方便创建Inter接口的子类对象,可以用一个类先把接口中的所有方法都空实现。该类创建对象没有意义,所以可以将该类抽象。这就是传说中的没有抽象方法的抽象类。
  1. interface Inter{  
  2.     public abstract void show1();  
  3.     public abstract void show2();  
  4.     public abstract void show3();  
  5.     public abstract void show4();  
  6. }  
  7. abstract class Demo implements Inter{//没有抽象方法的抽象类,方便创建接口的子类对象。  
  8.     //private Demo(){} 不抽象,光私有化构造函数是不可以的。  
  9.     //因为Demo类是需要被子类继承的,子类对象初始化是要访问父类构造函数的,不可以私有化。  
  10.     public void show1(){}  
  11.     public void show2(){}//空实现  
  12.     public void show3(){}  
  13.     public void show4(){}  
  14. }  
  15. class DemoA extends Demo /*implements Inter*/{  
  16.     public void show1(){  
  17.         System.out.println("show1");  
  18.     }  
  19. }  
  20. class DemoB extends Demo /*implements Inter*/{  
  21.     public void show3(){  
  22.         System.out.println("show3");  
  23.     }  
  24. }  
  25. class InterfaceDemo4{  
  26.     public static void main(String[] args){  
  27.           
  28.     }  
  29. }  
   接口的思想
        笔记本电脑的USB接口。
        1.接口的出现扩展了功能。
        2.接口其实就是暴露出来的规则。
        3.接口的出现降低了耦合性。解耦~
    接口的出现,产生了两方:一方在使用接口(笔记本),一方在实现接口(USB鼠标)。

    开发顺序:接口->使用接口的类->实现接口的类,这其中,使用接口的类面向的是接口。

  1. class Mouse{}  
  2. interface USB{}  
  3. class NewMouse extends Mouse implements USB{}  
    抽象类:用于描述事物的共性基本功能,是一个体系单元的共性内容的向上抽取。
    接口:用于定义的都是事物的额外扩展功能。
    共性:都是不断向上抽取的结果。
    抽象类和接口的区别:
    1.类与类之间是继承关系,而且只能单继承
       类与接口之间是实现关系,而且可以多实现
    2.抽象类中可以定义抽象和非抽象方法,子类可以直接使用,或者覆盖使用。
       接口中定义的都是抽象方法,子类必须全部实现才可以使用。
    3.抽象类使用的是 is a 关系
       接口使用的是 like a 关系
    4.抽象类的成员修饰符可以自定义(除了abstract部分前面说的那些限制条件)
       接口中的成员修饰符都是固定的。(public static final 和 public abstract)
    5.抽象类有构造函数
       接口没有构造函数

  1. abstract class 犬{  
  2.     public abstract void 吃();  
  3.     public abstract void 叫();     
  4. }  
  5. interface 缉毒  
  6. {  
  7.     public abstract void 缉毒();  
  8. }  
  9. class 缉毒犬 extends 犬 implements 缉毒{  
  10.     public void 吃(){}  
  11.     public void 叫(){}  
  12.     public void 缉毒(){}  
  13. }  
多态

    下面我们再来说面向对象核心思想的最后一个特征:多态。

    多态在程序中的体现:父类的引用或者接口的引用指向了子类的对象。
    多态的好处:提高了代码的扩展性。
    多态的弊端:不能使用子类的特有方法。(即访问的局限性)
    多态的前提:
        1.必须有关系,继承,实现。
        2.通常有覆盖。
    多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。

  1. abstract class Animal{  
  2.     public abstract void eat();  
  3. }  
  4. class Dog extends Animal{  
  5.     public void eat(){  
  6.         System.out.println("bones");  
  7.     }  
  8.     public void lookHome(){  
  9.         System.out.println("look home");  
  10.     }  
  11. }  
  12. class Cat extends Animal{  
  13.     public void eat(){  
  14.         System.out.println("fish");  
  15.     }  
  16.     public void catchMouse(){  
  17.         System.out.println("catch mouse");  
  18.     }  
  19. }  
  20. class Pig extends Animal{  
  21.     public void eat(){  
  22.         System.out.println("si liao");  
  23.     }  
  24.     public void gongDi(){  
  25.         System.out.println("gong di");  
  26.     }  
  27. }  
  28. class DuotaiDemo{  
  29.     public static void main(String[] args){  
  30.         /* 
  31.         Animal a = new Dog(); 
  32.         a.eat();//子类方法覆盖父类,运行的是子类方法 
  33.         */  
  34.         method(new Cat());  
  35.     }  
  36.     //当面对共性类型时,所有的子类对象都可以接收,说明提高了代码的扩展性。  
  37.     public static void method(Animal a){//a = new Dog(); a = new Cat(); a = new Pig();  
  38.         a.eat();  
  39.     }  
  40. }  
向上向下转型

    向上转型好处:隐藏了子类型,提高了代码的扩展性。

    向上转型弊端:只能使用父类中的功能,不能使用子类特有功能。功能被限定了。

    如果不需要面对子类型,通过提高扩展性,或者使用父类的功能即可完成操作,就使用向上转型。

    向下转型好处:可以使用子类型的特有功能。

    向下转型弊端:面对具体的子类型。向下转型有风险。容易发生ClassCastException。只要转换类型和对象类型不匹配就会发生。想要安全,必须要进行判断。

    判断一个对象是否匹配某一个类型,需要使用一个关键字 instanceof ,用法 对象 instanceof 类型。

    什么时候用向下转型:需要使用子类型的特有方法时。但一定要用 instanceof 判断。

  1. abstract class Animal{  
  2.     public abstract void eat();  
  3. }  
  4. class Dog extends Animal{  
  5.     public void eat(){  
  6.         System.out.println("bones");  
  7.     }  
  8.     public void lookHome(){  
  9.         System.out.println("look home");  
  10.     }  
  11. }  
  12. class Cat extends Animal{  
  13.     public void eat(){  
  14.         System.out.println("fish");  
  15.     }  
  16.     public void catchMouse(){  
  17.         System.out.println("catch mouse");  
  18.     }  
  19. }  
  20. class DuotaiDemo2{  
  21.     public static void main(String[] args){  
  22.         Animal a = new Cat();  
  23.         //a.eat();  
  24.         if (!(a instanceof Dog)){//判断对象是否实现了指定的接口或继承了指定的类  
  25.             System.out.println("类型不匹配");  
  26.             return;  
  27.         }  
  28.         Dog d = (Dog)a;  
  29.         d.eat();  
  30.         d.lookHome();  
  31.     }  
  32. }  
    转型过程中,至始至终,只有子类对象这一个实例在做着类型的变化。

    练习:

    毕姥爷:讲课。钓鱼。
    毕老师 extends 毕姥爷:讲课。看电影。
    要求体现多态,要看到向上转型,向下转型。

  1. class 毕姥爷{  
  2.     public void 讲课(){  
  3.         System.out.println("管理");  
  4.     }  
  5.     public void 钓鱼(){  
  6.         System.out.println("钓鱼");  
  7.     }  
  8. }  
  9. class 毕老师 extends 毕姥爷{  
  10.     public void 讲课(){  
  11.         System.out.println("java");  
  12.     }  
  13.     public void 看电影(){  
  14.         System.out.println("看电影");  
  15.     }  
  16. }  
  17. class DuoTaiTest{  
  18.     public static void main(String[] args){  
  19.         //多态形式  
  20.         毕姥爷 x = new 毕老师();//向上转型  
  21.         x.讲课();  
  22.         x.钓鱼();  
  23.         //要想使用毕老师的特有方法 看电影  
  24.         毕老师 y = (毕老师)x;//向下转型  
  25.         y.讲课();  
  26.         y.钓鱼();  
  27.         y.看电影();  
  28.     }  
  29.     //转型过程中,至始至终,只有子类对象这一个实例在做着类型的变化。  
  30. }  
多态在子父类成员上的特点

    多态中对成员的调用。
    1.成员变量
       当子父类中出现同名成员变量时,
       多态调用时,只看调用该成员变量的引用所属类中的成员变量。
       简单说:无论编译或者运行,都看等号左边的就哦了。
      (编译时不产生对象,只检查语法错误)

    2.成员函数
       当子父类中出现一模一样的函数时,多态调用,
       编译时,看的是引用变量所属的类中的方法。(编译时,还没有创建对象)
       运行时,看的是对象所属的类中的方法。(注意,此时父类方法,子类都已继承,若一模一样,则子类的覆盖)
       简单说:编译看左边,运行看右边
       成员方法动态绑定到当前对象上。

    3.静态方法
       当子父类中出现一模一样的函数时,多态调用,
       编译和运行是看引用变量所属的类中的方法。
       简单说:编译运行都是看左边
       其实,真正调用静态方法是不需要对象的,直接类名调用。
       因为静态方法绑定到该方法所属的类上,不所属于对象。

    注:

       

  1. class Fu{  
  2.     int num = 4;  
  3.     void show(){  
  4.         System.out.println("fu show");  
  5.     }  
  6.     static void staticMethod(){  
  7.         System.out.println("fu static method");  
  8.     }  
  9. }  
  10. class Zi extends Fu{  
  11.     int num = 6;  
  12.     void show(){  
  13.         System.out.println("zi show");  
  14.     }  
  15.     static void staticMethod(){  
  16.         System.out.println("zi static method");  
  17.     }  
  18. }  
  19. class DuoTaiDemo3{  
  20.     public static void main(String[] args){  
  21.         Fu f = new Zi();  
  22.         System.out.println(f.num);  
  23.           
  24.         f.show();  
  25.           
  26.         f.staticMethod();  
  27.     }  
  28. }  
    4.this.成员变量

       始终代表的是本类引用
       执行哪个类的成员函数,那个成员函数中的this就代表那个类的引用。

  1. class Fu{  
  2.     int num = 5;  
  3.     void show(){  
  4.         System.out.println("num = "+this.num);//this代表的是本类引用。//成员变量:编译运行看左边。  
  5.     }  
  6. }  
  7. class Zi extends Fu{  
  8.     int num = 6;  
  9. }  
  10. class DuoTaiTest2{  
  11.     public static void main(String[] args){  
  12.         Fu f = new Zi();  
  13.         f.show();//运行看右边。右边是Zi类对象,其实Zi类也是有show()函数的,是继承的Fu类的。所以运行的是父类的show。  
  14.     }  
  15. }  
  16. class Fu{  
  17.     int num = 5;  
  18.     void show(){}  
  19. }  
  20. class Zi extends Fu{  
  21.     int num = 6;  
  22.     void show(){  
  23.         System.out.println("num = "+this.num);//此时,这个this所在的show函数在Zi类中,所以,这个this代表Zi类对象,只要是执行Zi的show函数,都是打印Zi的num值。  
  24.     }  
  25. }  
  26. class DuoTaiTest2{  
  27.     public static void main(String[] args){  
  28.         Fu f = new Zi();  
  29.         f.show();//成员函数,编译看左边,运行看右边。运行的是子类的show。  
  30.     }  
  31. }  
    多态练习:USB接口。

  1. //先定义一个规则。java中可以通过接口的形式来完成规则的定义,进行解耦。  
  2. //让设备和笔记本的耦合性降低,易于扩展和维护。  
  3. interface USB{  
  4.     public abstract void open();  
  5.     public abstract void close();  
  6. }  
  7. class NoteBook{  
  8.     public void run(){  
  9.         System.out.println("NoteBook run");  
  10.     }  
  11.     /** 
  12.     使用符合规则的外围设备。这样就不用每次面对具体的类型, 
  13.     后期加进来的设备都符合这个规则,只要面对规则就可以了。 
  14.     */  
  15.     public void useUSB(USB usb){//定义了一个接口类型的引用//USB usb = new MouseByUSB();//多态提高了笔记本的扩展性  
  16.         if (usb != null){  
  17.             usb.open();  
  18.             usb.close();  
  19.         }  
  20.     }  
  21. }  
  22. class MouseByUSB /*extends Mouse*/ implements USB{  
  23.     public void open(){  
  24.         System.out.println("mouse open");  
  25.     }  
  26.     public void close(){  
  27.         System.out.println("mouse close");  
  28.     }  
  29. }  
  30. class KeyBoardByUSB/*extends KeyBoard*/ implements USB{  
  31.     public void open(){  
  32.         System.out.println("keyboard open");  
  33.     }  
  34.     public void close(){  
  35.         System.out.println("keyboard close");  
  36.     }  
  37. }  
  38. class USBTest{  
  39.     public static void main(String[] args){  
  40.         NoteBook book = new NoteBook();  
  41.         book.run();  
  42.         book.useUSB(null);  
  43.         book.useUSB(new MouseByUSB());  
  44.         book.useUSB(new KeyBoardByUSB());  
  45.     }  
  46. }  
Object类

    Object:所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能。
    具体方法:
    1,boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。

          而根据对象的属性不同,判断对象是否相同的具体内容也不一样。

          所以在定义类时,一般都会复写equals方法,建立本类特有的判断对象是否相同的依据。

    2,String toString():将对象变成字符串。

          默认返回的格式:类名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())

          为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式。 
    3,Class getClass():获取任意对象运行时的所属字节码文件对象
    4,int hashCode():返回该对象的哈希码值。支持此方法是为了提高哈希表的性能。
    通常equals,toString,hashCode,在应用中都会被复写,建立具体对象的特有的内容。

  1. //java.lang.Object  
  2. class Person extends Object{  
  3.     private int age;  
  4.     private String name;  
  5.     Person(String name, int age){  
  6.         this.age = age;  
  7.         this.name = name;  
  8.     }  
  9.     public boolean equals(Object obj){//覆盖父类方法 //Object obj = new Person();  
  10.         //提高效率。如果两个引用指向的是同一个对象,不用再转换并比较内容了。直接判断地址就可以。  
  11.         if (this == obj)  
  12.             return true;  
  13.         //Object.age是错误的,因为Object中没有age属性。  
  14.         //要想使用子类对象的特有属性或者行为,必须对其进行向下转型。并且需要进行类型判断。  
  15.         if (!(obj instanceof Person))  
  16.             throw new ClassCastException("类型错误");  
  17.         Person p = (Person)obj;  
  18.         //判断两个人的名字是否相同,不要用==,字符串本身就是一个对象。使用String类的equals方法判断。  
  19.         return this.name.equals(p.name) && this.age == p.age;  
  20.     }  
  21.     /** 
  22.     建立Person对象特有的字符串表现形式。只要覆盖toString方法即可。 
  23.     */  
  24.     public String toString(){  
  25.         return "Person [ name = "+this.name+", age = "+this.age+" ]";  
  26.     }  
  27. }  
  28. class ObjectDemo{  
  29.     public static void main(String[] args){  
  30.         Person p1 = new Person("lisi",22);  
  31.         Person p2 = new Person("wanger",23);  
  32.         System.out.println(p1);//Person@1db9742  
  33.         System.out.println(p1.toString());  
  34.         System.out.println(p2.toString());  
  35.         System.out.println(p1.equals(p2));//判断的是对象的内容,用equals。  
  36.         System.out.println(p1 == p2);//判断的是对象的地址。  
  37.           
  38.     }  
  39. }  
内部类

    内部类其实就是将类定义到了另一个类内部。A类要直接访问B类中的成员时,可以将A类定义到B类中。作为B类的内部类存在。

    访问规则:内部类可以直接访问外部类中的成员。外部类要想访问内部类,只能创建内部类的对象来访问。

    当内部类定义在外部类中的成员位置上,可以使用一些成员修饰符修饰 private、static。

   1:默认修饰符。

       直接访问内部类格式:外部类名.内部类名 变量名 =  外部类对象.内部类对象;

       Outer.Inner in = new Outer.new Inner();//这种形式很少用。

       但是这种应用不多见,因为内部类之所以定义在内部就是为了封装。

       想要获取内部类对象通常都通过外部类的方法来获取。这样可以对内部类对象进行控制。

   2:私有修饰符。

       通常内部类被封装,都会被私有化,因为封装性不让其他程序直接访问。 

   3:静态修饰符。

       如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。

       注意;如果内部类中定义了静态成员,那么该内部类必须是静态的。

   内部类编译后的文件名为:“外部类名$内部类名.java”;

  1. class Outer{  
  2.     private static int num = 4;  
  3.     class Inner{//内部类,相当于外部类中的一个成员。可以被成员修饰符所修饰。//外部类先加载,如果没有用到非静态内部类,非静态内部类的class文件一直不加载。  
  4.         static final int count = 5;//在非静态的内部类中只允许定义静态的常量。不能定义其它静态成员。//这是因为,非静态内部类如果被调用,需要new Inner()对象,而静态成员不需要对象即可调用,这是矛盾的。  
  5.         void show(){  
  6.             System.out.println(num);//Outer.this.num  
  7.         }  
  8.     }  
  9.     static class Inner2{//静态内部类。相当于一个外部类。随着Outer的加载而加载。  
  10.         void show2(){  
  11.             System.out.println("show2..."+num);  
  12.         }  
  13.         static void show3(){  
  14.             System.out.println("show3..."+num);  
  15.         }  
  16.     }  
  17.     public void method(){  
  18.         Inner in = new Inner();  
  19.         in.show();  
  20.     }  
  21. }  
  22. class InnerClassDemo{  
  23.     public static void main(String[] args){  
  24.         Outer out = new Outer();  
  25.         out.method();  
  26.           
  27.         //=========非静态,非私有的内部类访问方式=========  
  28.         Outer.Inner in = new Outer().new Inner();//需要外部类对象  
  29.         in.show();  
  30.           
  31.         //=========静态,非私有的内部类访问方式1,访问非静态成员=========  
  32.         Outer.Inner2 in = new Outer.Inner2();//不需要外部类对象  
  33.         in.show2();  
  34.           
  35.         //=========静态,非私有的内部类访问方式2,访问静态成员=========  
  36.         Outer.Inner2.show3();  
  37.     }  
  38. }  
     为什么内部类就可以直接访问外部类中的成员?

    那是因为内部类持有了外部的引用:外部类名.this

  1. class Outer{  
  2.     int num = 2;  
  3.     class Inner{  
  4.         int num = 3;  
  5.         void show(){  
  6.             int num = 4;  
  7.             System.out.println("show..."+Outer.this.num);//Inner.this.num  
  8.         }  
  9.     }  
  10.     public void method(){  
  11.         new Inner().show();  
  12.     }  
  13. }  
  14. class InnerClassDemo2{  
  15.     public static void main(String[] args){  
  16.         new Outer().method();  
  17.     }  
  18. }  
    内部类可以定义在外部类中的成员位置上,也可以定义在外部类中的局部位置上。

   注意:局部内部类,只能访问被final修饰的局部变量

   因为非final修饰的,生命周期不够,因为局部变量消失,建立的对象还没有消失。

  1. class Outer{  
  2.     private int num = 4;  
  3.     public void method(){  
  4.         final int x = 5;  
  5.         class Inner{  
  6.             void show(){  
  7.                 System.out.println("x = "+x);  
  8.                 System.out.println("num = "+num);  
  9.             }  
  10.         }  
  11.     }  
  12. }  
  13. class InnerClassDemo2{  
  14.     public static void main(String[] args){  
  15.         new Outer().method();  
  16.     }  
  17. }  
匿名内部类

    匿名内部类:简化书写的内部类。
    前提:内部类需要继承或者实现外部的类或者接口。
    格式:new 父类or接口名(){定义子类成员或者覆盖父类方法}.方法。
    匿名内部类其实就是一个子类对象。
    new Demo();---------后面加;号, 就是父类对象。
    new Demo(){}-------后面加{}号,就是子类对象。

  1. abstract class Demo{  
  2.     abstract void show();  
  3. }  
  4. class Outer{  
  5.     private int num = 4;  
  6.     public void method(){  
  7.         new Demo(){  
  8.             public void show(){  
  9.                 System.out.println("show..."+num);  
  10.             }  
  11.         }.show();  
  12.     }  
  13. }  
  14. class InnerClassDemo3{  
  15.     public static void main(String[] args){  
  16.         new Outer().method();  
  17.     }  
  18. }  
    当出现多个方法时,可以如下使用:

  1. interface Inter{  
  2.     public abstract void show1();  
  3.     public abstract void show2();  
  4. }  
  5. class Outer{  
  6.     private int num = 2;  
  7.     /*class Inner implements Inter{ 
  8.         public void show1(){} 
  9.         public void show2(){} 
  10.     }*/  
  11.     public void method(){  
  12.         //Inner in = new Inner();  
  13.         //in.show1();  
  14.         //in.show2();  
  15.         Inter in = new Inter(){  
  16.             public void show1(){}  
  17.             public void show2(){}  
  18.         };  
  19.         in.show1();  
  20.         in.show2();  
  21.     }  
  22. }  
  23. class InnerClassDemo4{  
  24.     public static void main(String[] args){  
  25.         //new Outer().method();  
  26.         new Inner();//不可以。主函数是静态的,无法访问静态成员。静态方法中,不可以出现this。  
  27.         new InnerClassDemo4().new Inner();//可以。  
  28.     }  
  29.     class Inner{  
  30.       
  31.     }  
  32.     public void show(){  
  33.         this.new Inner();//可以。  
  34.     }  
  35. }  
    经典面试题:如下的1、2写法正确吗?有何区别?
  1. class Outer{  
  2.     /*class Inner extends Object{ 
  3.      
  4.     }*/  
  5.     public void method(){  
  6.         //1  
  7.         new Object(){  
  8.             public void show(){  
  9.                 System.out.println("show run");  
  10.             }  
  11.         }.show();//匿名内部类就是子类对象。子类对象.子类方法  
  12.         //2  
  13.         Object obj = new Object(){//object obj指向了自己的子类对象。对象向上提升为了Object。就不能调用子类的特有方法。  
  14.             public void show(){  
  15.                 System.out.println("show run");  
  16.             }  
  17.         };  
  18.         obj.show();//不可以。  
  19.     }  
  20. }  
  21. class InnerClassDemo5{  
  22.     public static void main(String[] args){  
  23.           
  24.     }  
  25. }  

    写法是正确,1和2都是在通过匿名内部类建立一个Object类的子类对象。

    区别:

    第一个可是编译通过,并运行。

    第二个编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,就被提升为了Object类型,而编译时检查Object类中是否有show方法,所以编译失败。

  1. class InnerClassDemo6 {  
  2.     +(staticclass Inner{  
  3.     void show(){}  
  4.     }  
  5.     public void method(){  
  6.         this.new Inner().show();//可以  
  7.     }  
  8.     public static void main(String[] args) {//static不允许this  
  9.         this.new Inner().show();//错误,Inner类需要定义成static  
  10.     }  
  11. }  
    经典笔试题:通过匿名内部类补足Outer类中的代码。

  1. interface Inter{  
  2.     void show();  
  3. ]  
  4. class Outer{//通过匿名内部类补足Outer类中的代码  
  5.       
  6. }  
  7. class InnerClassDemo6{  
  8.     public static void main(String[] args){  
  9.         Outer.method().show();  
  10.     }  
  11. }  
    分析:

    Outer.method():意思是Outer中有一个名称为method的方法,而且这个方法是静态的。

    Outer.method().show():当Outer类调用静态的method方法运算结束后的结果又调用了show方法,意味着:method()方法运算完一个是对象,而且这个对象是Inter类型的。

    答案:

  1. interface Inter{  
  2.     void show();  
  3. ]  
  4. class Outer{//通过匿名内部类补足Outer类中的代码  
  5.     public static Inter method(){  
  6.         return new Inter(){  
  7.             public void show(){}  
  8.         };  
  9.     }  
  10. }  
  11. class InnerClassDemo6{  
  12.     public static void main(String[] args){  
  13.         Outer.method().show();  
  14.     }  
  15. }  
    此外,当函数的参数是接口类型引用时,匿名内部类还可以作为方法的参数进行传递。

  1. interface Inter{  
  2.     public abstract void show();  
  3. }  
  4. class InnerClassDemo7{  
  5.     public static void main(String[] args){  
  6.         function(new Inter(){  
  7.             public void show(){}  
  8.         });//匿名内部类作为方法的参数进行传递  
  9.     }  
  10.     public static void function(Inter in){//如果function不是static,主函数是无法调用的  
  11.         in.show();  
  12.     }  
  13. }  

后面一片博客将会介绍,JavaSE面向对象中的异常、包。

阅读全文
0 0