首页 > 代码库 > 黑马程序员-内部类、 抽象类、接口
黑马程序员-内部类、 抽象类、接口
java面向对象中比较重要的知识还有内部类,抽象类、接口,这些和封装、继承、多态一起赋予java强大的面向对象的能力
1、抽象类
在面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的。如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。
创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样使用他们.抽象类还是有用的重构器,因为它们使我们可以很容易地将公共方法沿着继承层次结构向上移动。
抽象类的特点:
1:抽象方法只能定义在抽象类中,抽象类和抽象方法必须由abstract关键字修饰(可以描述类和方法,不可以描述变量)。
2:抽象方法只定义方法声明,并不定义方法实现。
3:抽象类不可以被创建对象(实例化)。
4:只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化。否则,该子类还是一个抽象类。
5: 抽象类只能单继承。
在使用抽象类时需要注意几点:
1、抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可。
2、抽象方法必须由子类来进行重写。
3、抽象类中有构造函数,用于给子类对象进行初始化。
4、只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含有其他方法。
5、抽象类中可以包含具体的方法,当然也可以不包含抽象方法。其实,抽象类和一般类没有太大的区别,都是在描述事物,只不过抽象类在描述事物时,有些功能不具体。所以抽象类和一般类在定义上,都是需要定义属性和行为的。只不过,比一般类多了一个抽象函数。而且比一般类少了一个创建对象的部分。
6、抽象类中可以不定义抽象方法。抽象方法目的仅仅为了不让该类创建对象。
7、子类中的抽象方法不能与父类的抽象方法同名。
8、abstract不能与final并列修饰同一个类。
9、abstract 不能与private、static、final或native并列修饰同一个方法。
实例:
public abstract class Animal { //父类 public abstract void cry(); } public class Cat extends Animal{ //Cat继承了Amimal,并复写了父类的cry()方法 public void cry() { System.out.println("猫叫:喵喵..."); } } public class Dog extends Animal{ public void cry() { System.out.println("狗叫:汪汪..."); } } public class Test { public static void main(String[] args) { Animal a1 = new Cat(); //泛型特征,通过子类实例化父类a1, Animal a2 = new Dog(); a1.cry(); //a1调用方法是被子类复写了的 a2.cry(); } }
运行结果是:
猫叫:喵喵...
狗叫:汪汪...
2、接口
接口是抽象类的延伸,java了保证数据安全是不能多重继承的,也就是说继承只能存在一个父类,但是接口不同,一个类可以同时实现多个接口,不管这些接口之间有没有关系,所以接口弥补了抽象类不能多重继承的缺陷。
接口本身就不是类,不能实例化一个接口就可以看出。如new Runnable();是错误的,我们只能new它的实现类。
接口是用来建立类与类之间的协议,它所提供的只是一种形式,而没有具体的实现。同时实现该接口的实现类必须要实现该接口的所有方法,通过使用implements关键字,他表示该类在遵循某个或某组特定的接口,同时也表示着“interface只是它的外貌,但是现在需要声明它是如何工作的。
在使用接口过程中需要注意如下几个问题:
1、Interface的方所有法访问权限自动被声明为public。确切的说只能为public,如果声明为protected、private,但是编译会出错!
2、接口中可以定义“成员变量”,但是是不可变的常量,因为接口中的“成员变量”会自动变为为public static final。
3、接口中不存在实现的方法。
4、实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。
5、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象
6、在实现多接口的时候一定要避免方法名的重复。
抽象类和接口的区别:
1:抽象类只能被继承,而且只能单继承。
接口需要被实现,而且可以多实现。
2:抽象类中可以定义非抽象方法,子类可以直接继承使用。
接口中都有抽象方法,需要子类去实现。
3:抽象类使用的是 is a 关系。
接口使用的 like a 关系。
4:抽象类的成员修饰符可以自定义。
接口中的成员修饰符是固定的。全都是public的
3.内部类
将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类命和$符号
访问特点:
?内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
? 而外部类要访问内部类中的成员必须要建立内部类的对象。
内部类分为成员内部类、方法内部类、匿名内部类。
1、成员内部类:
class Outer {
class Inner{}
}
编译上述代码会产生两个文件:Outer.class和Outer$Inner.class。
成员内部类内不允许有任何静态声明!
能够访问成员内部类的唯一途径就是通过外部类的对象!
class Outer { private int i = 10; public void makeInner(){ Inner in = new Inner();//在外部内类的方法中实例化内部类 in.seeOuter(); } class Inner{//定义了内部类 public void seeOuter(){ System.out.print(i); } } }
普通的类可以用this引用当前的对象,内部类也是如此。但是假若内部类想引用外部类当前的对象呢?用“外部类名”.this;的形式,
但是成员内部类更像一个成员变量和方法。可用的修饰符有:final、abstract、public、private、protected、strictfp和static。 一旦用static修饰内部类,它就变成静态内部类了。
2、方法内部类。
顾名思义,把类放在方法内。
class Outer { public void doSomething(){ class Inner{ public void seeOuter(){ } } } }
1方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
2、方法内部类对象不能使用该内部类所在方法的非final局部变量。
3与成员内部类不同,方法内部类更像一个局部变量。可以用于修饰方法内部类的只有final和abstract。
4、静态方法是没有this引用的,静态方法内的只能访问外部类的静态成员。
3、匿名内部类。
顾名思义 ,没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用
这种形式。匿名内部类其实就是一个匿名子类对象。想要定义匿名内部类:需要前提,内部类必须继承一个类或者实现接口。
匿名内部类的格式:
new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法。
A、继承式的匿名内部类。
class Car { public void drive(){ System.out.println("Driving a car!"); } } class Test{ public static void main(String[] args) { Car car = new Car(){ public void drive(){ System.out.println("Driving another car!"); } }; car.drive(); } }
结果输出了:Driving another car! Car引用变量不是引用Car对象,而是Car匿名子类的对象。
建立匿名内部类的关键点是重写父类的一个或多个方法。再强调一下,是重写父类的方法,而不是创建新的方法。因为用父类的引用不可能调用父类本身没有的方法!
B、接口式的匿名内部类。
interface Vehicle { public void drive(); } class Test{ public static void main(String[] args) { Vehicle v = new Vehicle(){ public void drive(){ System.out.println("Driving a car!"); } }; v.drive(); } }
上面的代码好像是在实例化一个接口。事实并非如此,接口式的匿名内部类是实现了一个接口的匿名类。而且只能实现一个接口。
C、参数式的匿名内部类。
class Bar{ void doStuff(Foo f){} } interface Foo{ void foo(); } class Test{ static void go(){ Bar b = new Bar(); b.doStuff(new Foo(){ public void foo(){ System.out.println("foofy"); } }); } }