抽象方法与抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类可以没有抽象方法。
抽象方法和抽象类的规则:抽象类必须使用abstract修饰符来修饰,抽象方法也必须使用abstract修饰符修饰,抽象方法不能有方法体;抽象类不能实体化,无法使用new关键字调用抽象类的构造器创建抽象类的实例。抽象类不包含抽象方法也不能实例化;抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口和枚举)5成分。抽象类的构造器不能实例化,只能用于被子类调用;含有抽象方法的类(包括直接定义了一个抽象方法,或者继承一个抽象父类但没有完全实现父类包含的抽象方法;实现一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。
abstract class abstractClass{ { System.out.println("abstractClass初始化块"); } String name; //抽象方法 //抽象方法没有方法体,不能用private修饰,抽象方法就是为了重写的 public abstract void test(); public abstract void test2(String name); } public class AbstractClassSon extends abstractClass{ public void test(){ System.out.println("子类重写抽象类不带参数的抽象方法"); } public void test2(String name){ System.out.println("子类重写抽象类带参数的抽象方法,参数值为: " + name); } public static void main(String[] args){ AbstractClassSon acs = new AbstractClassSon(); acs.test(); acs.test2("lilei"); } }
final不能与abstract同时使用,final修饰的不能被重写,抽象类就是为了重写。
abstract不能修饰成员变量,也不能修饰局部变量,没有抽象变量、抽象成员变量的说法;abstract也不能修饰构造器,没有抽象构造器的说法。
static和abstract不能同时使用,没有静态抽象方法。static修饰的方法是类方法,abstract修饰的方法是要被重写的,当抽象类没有被重写无法用一个不存在的方法调用类方法。但abstract和static不能互斥的,它们可以修饰内部类。
abstract关键字修饰的方法必须被子类重写才有意义,因此abstract修饰的方法不能定义为private访问权限。
抽象类不能创建实例,只能当成父类来创建。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类设计的随意性。
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行得更彻底,则可以提炼出一种更加特殊的抽象类-接口,接口中不能含有普通方法,接口中所有方法都是抽象方法。Java8进行了改进,允许定义默认方法,默认方法提供方法的实现。
一个接口可以有多个父接口,但接口只能继承接口不能继承类
interface 接口名 extends 父接口 implements 接口1, 接口2.。。
由于接口定义的是一种规范,所以接口不能包含构造器和初始化块。接口里可以包含成员变量(只能是静态变量)、方法(只能是抽象方法、类方法或默认方法)内部类(内部接口、枚举)
接口中所有成员都是public访问权限,接口中定义的静态常量而言,它们是接口相关的,因此系统会自动为这些成员变量添加static 和final修饰符。接口中定义成员变量系统会自动帮你添加public static final修饰符。接口定义的成员变量只能在定义时指定默认值。
public static final int MAX_SIZE = 36E;
接口定义的方法只能是抽象方法、类方法或默认方法,因此如果不是定义默认方法,系统将自动为普通方法添加abstract修饰符。接口中普通方法不能有方法实现,但类方法、默认方法都必须有方法实现。
interface InterfaceClass{ //抽象方法 public abstract void abstractMethod(); //默认方法 default void defaultMethod(){ System.out.println("接口中的默认方法"); } //接口的类方法 static void staticMethod(){ System.out.println("接口中的类方法"); } } public class InterfaceTest implements InterfaceClass{ //冲写接口的抽象方法 public void abstractMethod(){ System.out.println("重写接口的抽象方法"); } public static void main(String[] args){ InterfaceTest it = new InterfaceTest(); it.abstractMethod(); it.defaultMethod(); //staticMethod(); } }
接口完全支持多继承
interface ExtendsInterface{ int i = 10; public abstract void father1Method(); } interface ExtendsInterface2{ int j = 20; public abstract void father2Method(); } interface InterfaceClass extends ExtendsInterface, ExtendsInterface2{ //接口可以多继承 } public class InterfaceTest2 implements InterfaceClass{ public void father1Method(){ System.out.println("father1的抽象方法"); } public void father2Method(){ System.out.println("father2的抽象方法"); } public static void main(String[] args){ InterfaceTest2 it = new InterfaceTest2(); System.out.println("i = " + it.i); System.out.println("j = " + it.j); it.father1Method(); it.father2Method(); } }
一个类使用extends继承,但只能继承一个类;使用implements实现多个接口。实现接口的方法,必须用public访问控制修饰符。
接口不能显式继承任何类,但所有接口类型的引用变量都可以直接赋给Object类型的引用变量。
接口和抽象类共同点:接口和抽象类不能被实例化,他们位于继承树的顶端,用于被其他类实现和继承;接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类必须实现这些方法。
不同点:接口只能包含抽象方法、静态方法、默认方法,抽象类可以是包含普通方法;接口只能定义静态常量,不能定义普通成员变量,抽象类都可以;接口不包含构造器,抽象类可以包含;接口不包含初始化块,抽象类可以;一个类只能有一个直接父类,但可以实现多个接口。
把一个类放在另一个类的内部定义,成为内部类。
内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许统一包中其他类访问该类;内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员可以互相访问,但外部类不能访问内部类的实现细节;匿名内部类适合用于创建仅需要使用一次的类。
public class outClass{ //定义内部类 }
大部分时候,内部类都被作为成员内部类定义,而不是局部内部类。成员内部类是一种与成员变量、方法、构造器和初始化块相似的类成员;局部内部类和匿名内部类则不是类成员。
成员内部类分为两种:静态内部类和非静态内部类,静态内部类使用static修饰
public class InnerClass{ private String name; public InnerClass(String name){ this.name = name; } //内部类 public class NBLClass{ private int age; private String color; public NBLClass(){} public NBLClass(int age, String color){ this.age = age; this.color = color; } public void info(){ System.out.println("age = " + age + " color = " + color); System.out.println("访问外部类private修饰的成员变量,name的值为" + name); } } public void test(){ NBLClass nblc = new NBLClass(18, "green"); nblc.info(); } public static void main(String[] args){ InnerClass ic = new InnerClass("lilei"); ic.test(); } }
把这个类的定义放在另一个类的内部,所以就成了一个内部类,可以使用private修饰符修饰这个类
private class NBLClass{ private int age; private String color; public NBLClass(){} public NBLClass(int age, String color){ this.age = age; this.color = color; } public void info(){ System.out.println("age = " + age + " color = " + color); System.out.println("访问外部类private修饰的成员变量,name的值为" + name); } } public void test(){ NBLClass nblc = new NBLClass(18, "green"); nblc.info(); }
如果外部类成员变量、内部类成员变量与内部类里的方法的局部变量同名,则可通过this、外部类类名.this作为限定区分
public class InnerClass{ private String name; public InnerClass(String name){ this.name = name; } //内部类 private class NBLClass{ private String name; public NBLClass(String name){ this.name = name; } public void info(String name){ System.out.println(name); System.out.println(this.name); System.out.println(InnerClass.this.name); } } public void test(){ NBLClass nblc = new NBLClass("内部类的成员变量"); nblc.info("内部类的局部变量"); } public static void main(String[] args){ InnerClass ic = new InnerClass("外部类的成员变量"); ic.test(); } }
外部类要访问非静态内部类的成员,必须显式创建非静态内部类对象类调用访问其实例成员
public class InnerClass{ private int age = 100; //内部类 private class NBLClass{ private int InnerAge = 200; public void info(){ System.out.println("外部类age的值: " + age); } } public void test(){ //外部类访问非静态内部类必须显式创建内部类的实例,再调用变量 System.out.println("内部类InnerAge的值" + new NBLClass().InnerAge); } public static void main(String[] args){ InnerClass ic = new InnerClass(); ic.test(); } }
非静态内部类对象必须寄生在外部类对象中,而爱不累对象则不必一定有非静态内部类对象寄生其中。如果存在一个非静态内部类对象,则一定存在一个被它寄生的外部类。
Java不允许非静态内部类定义静态成员。非静态内部类不能有静态初始化块,但可以包含普通初始化块。非静态内部类普通初始化块的作用与外部类初始化块的一样。
静态内部类可以包含静态成员,也可以包含非静态成员。根据静态不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。
public InnerStaticClass{ private static int i = 100; static class InnerClass{ private static int j = 200; public void test(){ System.out.println("静态内部类只能访问外部类的静态成员: " + i); } }
静态内部类是外部类的一个静态成员,因此外部类的所有方法,所有初始化块可以使用静态内部类类定义变量、创建对象等。
外部类不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问内部类的类成员,也可以使用静态内部类对象作为调用者访问。
public class InnerStaticClass{ static class InnerClass{ private static int j = 100; private static int i = 200; } public static void main(String[] args){ //使用静态内部类类名访问变量 System.out.println(InnerClass.i); //创建静态内部类对象访问变量 System.out.println(new InnerClass().j); } }
Java还允许接口里定义内部类,皆苦定义的内部类默认使用public static 修饰。也就是接口内部类只能是静态内部类。
在外部类中使用内部类和普通类没什么区别,需要注意的是不能在外部类的静态成员中使用非静态内不来,静态成员不能访问非静态成员。
在外部类以外使用非静态内部类,则内部类不能用private修饰,private修饰只能在外部类中使用。
class InnerClass{ class In{ public In(String name){ System.out.println(name); } } } public class OutClass{ public static void main(String[] args){ //外部类以外访问内部类 //非静态内部类的构造器碧玺使用外部类对象调用 InnerClass.In icin = new InnerClass().new In("lilei"); } }
在外部类以外使用静态内部类
class InnerClass{ static class In{ public In(String name){ System.out.println(name); } } } public class OutClass{ public static void main(String[] args){ //外部类以外访问静态内部类 InnerClass.In icin = new InnerClass.In("lilei"); } }
其中new InnerClass.In()这里是类名.静态成员的格式访问静态成员,与非静态内部类创建外部类对象访问的方式不同。
局部内部类仅在该方法中有效,局部内部类不能在外部类的方法以外的地方使用,因此局部内部类也不能使用访问控制符和static修饰符修饰。
public class OutClass{ public static void main(String[] args){ class In{ int a = 10; } //外部类以外访问静态内部类 In i = new In(); System.out.println(i.a); } }
匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类或实现一个接口
匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象,因此不允许将匿名内部类定义成抽象类。
匿名内部类不能定义构造器,由于匿名内部类没有类名,无法定义构造器。
interface p{ } public class Test{ public void method(p s){ } public static void main(String[] args){ Test t = new Test(); t.method(new p(){ //匿名内部类 }); } }
当通过实现接口来创建匿名内部类时,匿名内部类也不能显式创建构造器,因此匿名内部类只有一个隐式的无参数构造器,故new接口名后的括号不能传入参数值
如果通过继承父类来创建匿名内部类,匿名内部类将拥有和父类相似的构造器,拥有相同的形参列表。
原文:https://www.cnblogs.com/zaijie/p/11037742.html