黑马程序员-Java学习笔记之抽象类,接口,多态和内部类

本文深入探讨Java中抽象类、接口、多态、Object类、内部类和匿名内部类的高级特性及其应用,详细解释每个概念的核心作用、特点及在实际编程中的使用方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 抽象类

抽象的定义

抽象:不具体,看不明白。抽象类表象体现。

在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法

    抽象就是从多个事物中将共性的,本质的内容抽取出来。

    例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。

 

抽象类

         Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。

        抽象类的由来:

        多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。

        例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。

 

3抽象类的特点

   

1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。

2:抽象方法只定义方法声明,并不定义方法实现。(就是没有{})。 

3:抽象类不可以被创建对象(实例化)

4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。。

注:抽象类中可以有非抽象的方法。

下面通过一个实例,来说明抽象类的使用:

 

4抽象类的细节:

 

1:抽象类中是否有构造函数?有,用于给子类对象进行初始化。

2:抽象类中是否可以定义非抽象方法?

可以。其实,抽象类和一般类没有太大的区别,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。

3:抽象关键字abstract和哪些不可以共存?final , private , static 

4:抽象类中可不可以不定义抽象方法?可以。抽象方法目的仅仅为了不让该类创建对象。

Example:

/*

当多个类中出现相同功能,但是功能主体不同。

这时可以进行向上抽取,这时,只抽取该功能定义,而不抽取功能主体。

抽象:看不懂。

抽象类的特点:

1,抽象方法一定在抽象类中。

2,抽象方法和抽象类必须被abstract关键字修饰。

3,抽象类不可以用new创建对象,因为调用抽象方法没意义。

4,抽象类中的抽象方法要被调用,必须由子类复写齐所有的抽象方法后,建立子类对象调用。

如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

抽象类和一般类没有什么不同。

该如何描述事务就如何描述事物,只不过,该事物出现论文一些看不懂的东西。

这些不确定的部分,也是该事物的功能,需要明确出现,但是无法定义主体。

通过抽象方法表示。

抽象类比一般类多了个抽象函数。就是在类中可以定义抽象方法。

抽象类不可以实例化。

特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

Example:


[java]  view plain copy
  1. */  
  2. //学生类  
  3. abstract class Student  
  4. {  
  5.     abstract void study();//抽象的学习方法  
  6.     void sleep()  
  7.     {  
  8.         System.out.println("躺着睡");  
  9.     }  
  10. }  
  11. //基础班学生  
  12. class BaseStudent extends Student  
  13. {  
  14.     void study()//复写  
  15.     {  
  16.         System.out.println("base study");  
  17.     }  
  18.   
  19. }  
  20. //就业班学生  
  21. class AdvStudent extends Student  
  22. {  
  23.     void study()  
  24.     {  
  25.         System.out.println("adv study");  
  26.     }  
  27.   
  28. }  
  29. class AbstractDemo  
  30. {  
  31.     public static void main(String[] args)  
  32.     {  
  33.         new BaseStudent().study();  
  34.         System.out.println("Hello world");  
  35.     }  
  36.   
  37. }  


5 模板方法设计模式:

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

Example:

[java]  view plain copy
  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("毫秒是:"+(end-start));  
  7.     }  
  8.     public abstract void code(); //抽象不确定的功能,让子类复写实现  
  9. }  
  10. class SubDemo extends GetTime{  
  11.     public void code(){ //子类复写功能方法  
  12.         for(int y=0; y<1000; y++){  
  13.             System.out.println("y");  
  14.         }  
  15.     }  
  16. }  


二 接口

1:是用关键字interface定义的。

2:接口中包含的成员,最常见的有全局常量、抽象方法。注意:接口中的成员都有固定的修饰符。

 

成员变量:public static final 

成员方法:public abstract 

interface Inter{

public static final int x = 3;

public abstract void show();

}

(就是没有{})

3:接口中有抽象方法,说明接口不可以实例化。接口的子类必须实现了接口中所有的抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。

4:类与类之间存在着继承关系,类与接口中间存在的是实现关系。

继承用extends  ;实现用implements 

5:接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良后的结果。java将多继承机制通过多现实来体现。 

6:一个类在继承另一个类的同时,还可以实现多个接口。所以接口的出现避免了单继承的局限性。还可以将类进行功能的扩展。

7:其实java中是有多继承的。接口与接口之间存在着继承关系,接口可以多继承接口。

 

接口都用于设计上,设计上的特点:(可以理解主板上提供的接口)

1:接口是对外提供的规则。

2:接口是功能的扩展。

3:接口的出现降低了耦合性。

 

抽象类与接口:

抽象类:一般用于描述一个体系单元,将一组共性内容进行抽取,特点:可以在类中定义抽象内容让子类实现,可以定义非抽象内容让子类直接使用。它里面定义的都是一些体系中的基本内容。

接口:一般用于定义对象的扩展功能,是在继承之外还需这个对象具备的一些功能。

 

抽象类和接口的共性:都是不断向上抽取的结果。

 

抽象类和接口的区别:

1:抽象类只能被继承,而且只能单继承。

接口需要被实现,而且可以多实现。 

2:抽象类中可以定义非抽象方法,子类可以直接继承使用。

接口中都有抽象方法,需要子类去实现。

3:抽象类使用的是  is a 关系。

接口使用的 like a 关系。 

4:抽象类的成员修饰符可以自定义。

接口中的成员修饰符是固定的。全都是public的。

 

在开发之前,先定义规则,AB分别开发,A负责实现这个规则,B负责使用这个规则。至于A是如何对规则具体实现的,B是不需要知道的。这样这个接口的出现就降低了AB直接耦合性。 

Example:


[java]  view plain copy
  1. //定义一个接口。  
  2. interface Inter  
  3. {  
  4.     public static final int NUM=3;  
  5.     public abstract void show();  
  6. }  
  7. //定义一个接口。  
  8. interface InterA  
  9. {  
  10.     public abstract void method();  
  11. }  
  12. class Demo  
  13. {  
  14.     public void function()  
  15.     {  
  16.     }  
  17. }  
  18. //定义一个类实现两个接口。  
  19. class Test extends Demo implements Inter,InterA  
  20. {  
  21.     public void show()//复写方法。  
  22.     {  
  23.     }  
  24.     public  void method()  
  25.     {  
  26.     }  
  27.   
  28. }  
  29. class InterfaceDemo  
  30. {  
  31.     public static void main(String[] args)  
  32.     {  
  33.         Test t=new Test();  
  34.         System.out.println(t.NUM);  
  35.         System.out.println(Test.NUM);  
  36.         System.out.println(Inter.NUM);  
  37.     }  
  38.   
  39. }  



三 多态

1概述

多态:面向对象特征之一,函数本身就具备多态性,某一种事物有不同的具体的体现。

2多态的前提

1:必须要有关系,比如继承、或者实现。

2:通常会有覆盖操作。

3体现

体现:父类引用或者接口的引用指向了自己的子类对象。

//Animal a = new Cat();

好处和坏处

多态的好处:提高了程序的扩展性。

多态的弊端:当父类引用指向子类对象时,虽然提高了扩展性,但是只能访问父类中具备的方法,不可以访问子类中特有的方法。(前期不能使用后期产生的功能,即访问的局限性)。

5 多态的出现思想上也做着变化

多态的出现思想上也做着变化:以前是创建对象并指挥对象做事情。有了多态以后,我们可以找到对象的共性类型,直接操作共性类型做事情即可,这样可以指挥一批对象做事情,即通过操作父类或接口实现。

 

Example:


[java]  view plain copy
  1. //定义一个父类动物。  
  2. abstract class Animal  
  3. {  
  4.     public abstract void eat();  
  5. }  
  6. //子类小狗继承父类动物类。  
  7. class Dog extends Animal  
  8. {  
  9.     //复写吃的方法。  
  10.     public void eat()  
  11.     {  
  12.         System.out.println("吃骨头");  
  13.     }  
  14.     // 小狗特有的方法看家护院。  
  15.     public static void kanJia()  
  16.     {  
  17.         System.out.println("看家护院");  
  18.     }  
  19. }  
  20. class DuoTaiDemo  
  21. {  
  22.     public static void main(String[] args)  
  23.     {  
  24.         Animal a=new Dog();//多态,父类引用指向子类对象。  
  25.         a.eat();  
  26.         //a.kanJia();错误,因为引用变量中没有该方法。  
  27.         Dog d=new Dog();  
  28.         d.kanJia();  
  29.         System.out.println("Hello world!");  
  30.     }  
  31.   
  32. }  


6 多态在子父类中的成员上的体现的特点

1,成员变量:在多态中,子父类成员变量同名。

在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误)

运行时期:也是参考引用型变量所属的类中是否有调用的成员。(只有多态,父类或者接口引用指向自己子类对象时才会发生。)

简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。


Example:


[java]  view plain copy
  1. class Person  
  2. {  
  3.     int num=5;  
  4. }  
  5. class Student extends Person  
  6. {  
  7.     int num=8;  
  8. }  
  9. class DuoTaiDemo  
  10. {  
  11.     public static void main(String[] args)  
  12.     {  
  13.         Person p=new Student();  
  14.         Student p1=new Student();  
  15.   
  16.         System.out.println(p.num);//5  
  17.         System.out.println(p1.num);//8  
  18.     }  
  19.   
  20. }  

再说的更容易记忆一些:成员变量 --- 编译运行都看 = 左边。

2,成员函数。

编译时期:参考引用型变量所属的类中是否有调用的方法。

运行事情:参考的是对象所属的类中是否有调用的方法。

为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。

简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。

更简单:成员函数 --- 编译看 = 左边,运行看 = 右边。

3,静态函数。 

编译时期:参考的是引用型变量所属的类中是否有调用的成员。

运行时期:也是参考引用型变量所属的类中是否有调用的成员。

为什么是这样的呢?因为静态方法,其实不所属于对象,而是所属于该方法所在的类。

调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。

简单说:静态函数 --- 编译运行都看 = 左边。


四 Object

概述

Object:所有类的直接或者间接父类,Java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个最顶层的类中的,该类中定义的就是所有对象都具备的功能。

 

2 具体方法

1,boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象地址。

而根据对象的属性不同,判断对象是否相同的具体内容也不一样。所以在定义类时,一般都会复写equals方法,建立本类特有的判断对象是否相同的依据。

public boolean equals(Object obj){

if(!(obj instanceof Person))

return false;

Person p = (Person)obj;

return this.age == p.age;

}

2,String toString():将对象变成字符串;默认返回的格式:类名@哈希值 = getClass().getName() + '@' + Integer.toHexString(hashCode())

为了对象对应的字符串内容有意义,可以通过复写,建立该类对象自己特有的字符串表现形式。 

public String toString(){

return "person : "+age;

}

3,Class getClass():获取任意对象运行时的所属字节码文件对象。//Class类中的方法,注意和class的区别。

4,int hashCode():返回该对象的哈希码值。支持此方法是为了提高哈希表的性能。

 

通常equals,toString,hashCode,在应用中都会被复写,建立具体对象的特有的内容。

 

 

五 内部类

概述

如果A类需要直接访问B类中的成员,而B类又需要建立A类的对象。这时,为了方便设计和访问,直接将A类定义在B类中。就可以了。A类就称为内部类。

当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。如定义一个描述人的类,而手、心脏等都属于人,然它们又有自己的功能描述,这时可以在人这个描述类中,定义一个描述心脏的类,也就是内部类。

编译时,如果代码中有内部类,生成的class文件中会含有这样的文件:Test$1.class。编译器将会把内部类翻译成用$(美元符号)分隔外部类名和内部类名的常规类文件。这是内部类的一种编译现象。

内部类访问规则

     内部类可以直接访问外部类中的成员,包括私有。

为什么内部类可以直接访问外部类中的成员呢?

那是因为内部中都持有一个外部类的引用。这个是引用是 外部类名.this 

而外部类要访问内部类,必须建立内部类对象。

Exampel:


[java]  view plain copy
  1. class Outer{  
  2.     int num = 4;      
  3.     class  Inner {  
  4.         void show(){  
  5.             System.out.println("inner show run "+num);            
  6.         }  
  7.     }  
  8.     public void method(){  
  9.         Inner in = new Inner();//创建内部类的对象。  
  10.         in.show();//调用内部类的方法。   
  11.     }  
  12. }  


内部类格式

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

1:默认修饰符。

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

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

但是这种应用不多见,因为内部类之所以定义在内部就是为了封装。想要获取内部类对象通常都通过外部类的方法来获取。这样可以对内部类对象进行控制。

2:私有修饰符。

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

3:静态修饰符。

在外部类中直接访问静态内部类的非静态成员:new Outer.Inner().show();//这个show()是非静态。

  在外部类中直接访问静态内部类的静态成员:Outer.Inner.show(); //这个show()是静态方法。

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

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

当外部类中的静态方法访问内部类时,内部类也必须是静态的。

Example:


[java]  view plain copy
  1. class Outer  
  2. {  
  3.     int x = 2;  
  4.     void method(final int a)  
  5.     {  
  6.         final int y = 3;  
  7.         //局部内部类  
  8.                 class Inner  
  9.         {  
  10.             void function()  
  11.             {  
  12.                 System.out.println(y);  
  13.             }  
  14.         }  
  15.         new Inner().function();//使用局部内部类中的方法。  
  16.     }  
  17. }  
  18. class  InnerClassDemo  
  19. {  
  20.     public static void main(String[] args)   
  21.     {  
  22.         Outer out = new Outer();  
  23.         out.method(3;//打印3  
  24.         out.method(4);//打印4  
  25.     }  
  26. }  



匿名内部类

匿名内部类:没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式。匿名内部类其实就是一个匿名子类对象。想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口。

匿名内部类的格式:new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法。

匿名内部类的使用场景:

当函数的参数是接口类型引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。

其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。

 

Example:

[java]  view plain copy
  1. interface InnerDemo  
  2. {  
  3.     public abstract void method();  
  4. }  
  5. class Inner  
  6. {  
  7.     public static void main(String[]args)  
  8.     {  
  9.         show(new InnerDemo()  
  10.         {  
  11.             public void method()  
  12.             {  
  13.                 System.out.println("hello");  
  14.             }  
  15.         });  
  16.   
  17.     }  
  18.     public static void show(InnerDemo i)  
  19.     {  
  20.         i.method();  
  21.     }  
  22.       
  23. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值