为何要定义抽象方法:若是定义某个方法时不能肯定该方法的具体实现细节; 好比定义 Person 类的 eat 方法时, 不能肯定其具体实现细节,由于中国人、 西方国家的人、 南亚国家的人吃饭方式不同。 能够把该方法定义成一个抽象方法,具体 的实现细节,交给其后代(子类)来实现。java
使用 abstract 关键字修饰方法的定义,方法体必须为空(不然就不是抽象方法),抽象方法必须是非静态的(抽象方法不能被 static 修饰), 抽象方法不能被 final 修饰、 不能被 private 修饰.ide
[ 修饰符 ] abstract 返回值类型 methodName() ; //注意这里没有 { }
为何要定义抽象类:定义抽象方法的类, 必须被定义成抽象类
抽象类的定义方法设计
[ 修饰符 ] abstract class className { //使用 abstract 修饰类定义 }
/** * 为何要有抽象类 * 一、含有抽象方法的类,必须被定义成抽象类; * 可是,抽象类未必非要有抽象方法 * 二、若是指望当前类不能被实例化, * 而是交给子类完成实例化操做,能够定义抽象类 * (抽象类有构造方法,抽象类不能被实例化(直接建立该类的对象)) * Person p = new Person(); // 错误的 */ public abstract class Person { // 只要有花括号,就能够执行,这样的方法已经实现过了 /**当一个方法在定义时没法肯定其实现细节(具体处理什么、怎么处理) * 若是一个方法不是native 修饰的, * 当它没有方法体时,这个方法是不能被执行的,此时这个方法就是一个抽象的方法, * 须要使用抽象关键字来修饰(abstract) */ public abstract void eat(String food); /** * abstract 修饰方法时,不能与 static 、 final连用 */ } /** * 子类继承某个抽象类 * 一、若是子类依然不肯定某个方法的实现细节(不实现继承自父类的抽象方法), * 则能够将该类继续声明为抽象类 * 二、若是子类不但愿是抽象类,必须实现继承自父类的抽象方法 */ public class Sinaean extends Person{ public Sinaean(){ super(); } // 这个方法再也不是抽象方法了,并且能够有方法体 @Override public void eat(String food) { System.out.println("中国人大部分都用筷子吃"+ food); } } public class Thai extends Person{ @Override public void eat(String food) { System.out.println("泰国人有时候用手抓着吃: "+ food); } } /** * 建立抽象类的实例: * 一、建立其子类类型的实例(这是本质) * 二、能够经过静态方法来得到其实例(本质仍是建立子类类型对象 ) */ public class Main { public static void main(String[] args) { // 不能实例化Person 类型:抽象类不能被实例化 // Person p = new Person();//Cannot instantiate the type Person // 声明一个Person 类型的变量p(p的编译时类型是 Person) // 建立抽象类的子类类型的对象,并将其堆内存中首地址赋值给栈空间中的p变量 Person p =new Sinaean(); p.eat("火锅"); System.out.println("运行时类型: " + p.getClass());System.out.println("内存中的首地址是: "+ System.identityHashCode(p)); // 建立抽象类的子类类型的对象,并将其堆内存中首地址赋值给栈空间中的p变量 // p 变量中原来存储的地址将被覆盖 p = new Thai(); p.eat("米饭"); System.out.println("运行时类型: " + p.getClass()); System.out.println("内存中的首地址是: "+ System.identityHashCode(p)); Calendar c = Calendar.getInstance(); // 经过静态方法来得到一个实例 Class<?> clazz = c.getClass();// 得到c 所引用的对象的真实类型(运行时类型) System.out.println(clazz); Class<?> superClass = clazz.getSuperclass();// 得到clazz的父类 System.out.println(superClass); } }
抽象类的特色 一、抽象类【有构造】,可是不能被实例化 抽象类的构造方法专供子类调用(构造方法也是能够执行的) 二、抽象类中能够有抽象方法,也能够没有 含有抽象方法的类必须是抽象类(参看Person中的第一点) 抽象类中能够没有抽象方法(参看Person中的第二点) 三、怎么建立抽象类的实例:建立其子类类型的实例(这是本质) 待建立对象的子类类型必须是非抽象类 不必定非要是直接子类,间接子类也能够 能够经过静态方法来得到其实例(Calendar.getInstance() ) Calendar c = Calendar.getInstance(); 四、应该选择哪一种方式来建立抽象类的实例: a>、若是当前抽象类中有静态方法,则优先使用静态方法 b>、若是子类中有静态方法返回相应实例,用子类的静态方法 c>、寻找非抽象的子类,建立子类类型的对象便可 d>、本身继承这个类并实现其中的抽象方法,而后建立实例 注意:有时为了实现咱们的需求,可能会不调用静态方法来得到实例,而是选择建立子类对象
接口是一种比抽象类更抽象的类型;接口是从多个类似的类中抽象出来的规范: 它定 义了某一批类(接口的实现类或实现类的子类)所要必须遵循的规范。 接口只定义常量 或方法, 而不关注方法的实现细节,接口体现了规范和实现相分离的设计哲学。code
[ 修饰符 ] interface InterfaceName { 定义在接口中的常量 ( 0 到 n 个) 定义在接口中的抽象方法 ( 0 到 n 个) static 修饰的方法 ( 0 到 n 个) default 修饰的方法( 0 到 n 个) }
接口的继承使用 extends 关键字实现:对象
public interface Usb1 extends Usb {};
Java 语言中的接口能够继承多个接口: 多个接口之间使用 , 隔开 ( 英文状态的逗 号 );子接口能够继承父接口中的: 抽象方法、常量属性、内部类、枚举类继承
类能够实现接口:使用 implements 关键字来实现接口
接口中的属性默认都是 public 、 static 、 final 类型:这些成员必须被显式初始化;接口中的方法默认都是 public 、 abstract 类型的。内存
接口中根本就没有构造方法, 也就可能经过构造来实例化,但容许定义接口类型的引用变量,该引用变量引用实现了这个接口的类的实例。get
接口不能实现另外一个接口, 但能够继承多个接口。it
接口必须经过实现类来实现它的抽象方法,当某个类实现了某个接口时, 必须实现其中全部的抽象方法,或者是不实现其中的抽象方法, 而把该类定义成抽象类。
类只能继承一个类, 但能够实现多个接口,多个接口之间用逗号分开。
共同点: 接口和抽象类都不能被实例化 接口和抽象类都处于继承树的顶端 接口和抽象类均可以包含抽象方法 实现接口或继承抽象类的普通类必须实现其中的抽象方法 区别 抽象类中能够有非抽象方法, 接口中只能有抽象方法或static修饰的方法或default修饰的方法 一个类只能继承一个直接父类, 而接口能够实现多继承 抽象类可定义静态属性和普通属性, 而接口只能定义静态属性 抽象类有本身的构造, 接口彻底没有 抽象类中能够有代码块, 接口中不能够有
/** * 声明接口,并肯定接口中能够有什么 * 一、常量 * 二、抽象方法 * 三、 default 修饰的非抽象方法(JDK1.8开始)* 四、接口没有构造方法 */ public interface Usb { // 接口没有构造方法 // public Usb(){} /** * 接口中只能定义常量(没有不是否是常量的属性) * 一、接口中全部的属性默认都是 public static final 修饰的 * 二、常量的命名:全部字母都是大写,若是有多个单词,中间用下划线隔开 * */ int POWER_UNIT = 100 ;// 充当供电单位 /** * JDK1.8 以前 仅容许在接口中声明抽象方法 * 全部的方法都是 public abstrct 修饰的 */ void power(); /** * JDK1.8 开始,容许定义被default修饰的非抽象方法 * 这个方法是个public 修饰的非静态方法(子类或子接口能够重写) */ default void show(){ System.out.println("每次供电单位是: "+POWER_UNIT) ; } } /** * 一、类 能够实现接口,用关键字implements来完成实现 * 二、若是原本不但愿是抽象类,则须要实现从接口"继承"的全部抽象方法 */ public class MiUsb extends Object implements Usb { /** * MiUsb中都有什么 * 从Object中继承的全部方法 * 从Usb中继承的常量 * 从Usb中继承的default的方法(JDK1.8开始) * 实现了全部的抽象方法 */ @Override public void power() { System.out.println("小米Usb充电器,供电单位: "+POWER_UNIT); } @Override public void show() { Usb.super.show(); } } public class Test { public static void main(String[] args) { // 声明一个接口类型的引用变量Usb u = null; // 建立实现类的实例 并将其堆内存首地址赋值给u变量 u = new MiUsb(); u.power(); } } 一个类实现多个接口 public interface Transfer { void transmission(); } /** * 一、用接口继承接口 * 二、接口能够继承父接口中的常量、抽象方法、 default方法 * 三、一个接口能够继承多个接口,中间用逗号隔开就行 */ public interface UsbTypeC extends Usb , Transfer{} /** * 一个类能够实现多个接口,中间用逗号分隔开就能够 */ public class OppoUsb implements UsbTypeC,Usb{ @Override public void transmission() { System.out.println("Oppo手机"); } @Override public void power() { System.out.println("Oppo 手机,供电单位"+ POWER_UNIT); } } public class Test2 { public static void main(String[] args) { // 声明一个接口类型的引用变量 OppoUsb u = null; u = new OppoUsb(); u.power();// 实现了Usb接口中的方法 u.transmission();// 实现了Transfer接口中的方法 } }
内部类的分类以下:
成员内部类: 实例内部类 静态内部类 局部内部类: 匿名内部类
public class Human {/* 类体括号 */ public static void main(String[] args){ // main 方法的方法体开始 int a = 250; System.out.println(a); class ON{ // 局部内部类(Local Inner Class) } ON oo = new ON(); System.out.println(oo); class OFF{ // 局部内部类(Local Inner Class) } }// main 方法的方法体结束static String earth; // 属性:静态属性( 类属性 ) String name ; // 属性 :实例属性(实例变量) static class Country{ // 静态内部类[ static Inner Class] } class Head{// 实例内部类 (成员内部类) [ Member Inner Class ] } class Hand{// 实例内部类 } }
/** * 得到某个类内部的全部的静态内部类和全部的成员内部类 * 注意:不能得到到局部内部类 */ public class GetInnerClass { public static void main(String[] args) { Class<?> c = Human.class; // 得到 c 内部的内部类(静态内部类、成员内部类) Class<?>[] classes = c.getDeclaredClasses();// 得到本类内声明的非 局部内部类 for (int i = 0; i < classes.length; i++) { Class<?> cc = classes[i]; System.out.println(cc); } } }
也能够经过一个内部类获取本身声明在哪一个类内部
public class GetOutterClass { public static void main(String[] args) { Class<?> c = Human.Country.class; // 得到某个内部类声明在那个外部类中 Class<?> oc = c.getDeclaringClass(); // 得到声明本身的 那个类 System.out.println(oc); } }
public class GetInstance1 { public static void main(String[] args) { /** 静态内部类的实例 */ Human.Country c = new Human.Country(); System.out.println(c); /** 实例内部类的实例 */ Human h = new Human();// 建立外部类的实例 Human.Hand hand = h.new Hand();// 之外部类的实例 h 为基础,建立内部类的实例 System.out.println(hand); // 或者: Human.Head head= new Human().new Head(); System.out.println(head); } }
有一个局部内部类,它连名字都没有,则它就是匿名内部类,可是它有对应的.class文件。
新建一个新的 Class,叫作 TestAnonyous1。随后建立一个接口,叫作 USB,并提供一个方法(void transfer) 。具体在 TestAnonyous1 中的例子:用匿 名内部类实现接口。
/** * 建立匿名内部类 */ public class TestAnonymours1 { public static void main(String[] args) { // 编译时类型:变量u 声明的类型是USB // 用匿名内部类来实现接口 USB u = new USB(){ @Override public void transfer() { System.out.println("USB正在传输"); } };// 把USB当成尸体,结果鬼{}上身了,就能实例化了 u.transfer(); System.out.println(System.identityHashCode(u)); // 得到建立的实例的运行时类型 Class<?> c = u.getClass();// 任何一个对象均可以经过getClass来得到其 运行时类型 System.out.println(c); Class<?> oc = c.getDeclaringClass();// 尝试得到声明本身的那个外部类 System.out.println(oc);// null 说明 匿名内部类不是直接声明在类体内部的 Class<?>[] inters = c.getInterfaces(); for (int i = 0; i < inters.length; i++) { System.out.println(inters[i]); } } }
public abstract class AbstractUSB implements USB{ // 从实现的接口中继承了抽象方法 transfer } /** * 建立匿名内部类 */ public class TestAnonymours2 { public static void main(String[] args) { // 建立一个抽象类的实例(本质必定是建立其子类类型的实例) // 用匿名内部类来继承抽象类,并实现其中的抽象方法 AbstractUSB au = new AbstractUSB() { @Overridepublic void transfer() { System.out.println("AbstractUSB正在传输"); } }; au.transfer(); Class<?> c = au.getClass();// 得到au 对象的运行时类型 System.out.println("匿名内部类: "+ c.getName()); Class<?> sc = c.getSuperclass(); System.out.println("匿名内部类的父类: " + sc.getName() ); } }
/** * 建立匿名内部类 */ public class TestAnonymours3 { public static void main(String[] args) { // 用匿名内部类继承一个普通的类 // 并重写其中的方法 Object o = new Object(){ @Override public String toString(){ return "我是鬼。。 "; }}; System.out.println(o); System.out.println(o.getClass()); System.out.println(o.getClass().getSuperclass()); } }
一、内部类 嵌套在另外一个类内部的类 二、内部类的分类 直接写在类体括号内的: 静态内部类、非静态内部类(实例内部类、成员内部类) 不是直接写在类体括号内,好比写在方法中、写在代码块中:局部内部类 若是某个局部内部类连名字都没有,那它就是匿名内部类 三、问题: 对于 Human.java 来讲有一个与它对应的 Human.class 文件,内部类是否有对应的 .class 文件? 有.class 文件,对于静态内部类、实例内部类来讲,他们对应的 .class 的名称是: 外部类类名$内部类类名.class好比 Human 类中的 Country 类对应的 字节码文件的名称是:Human$Country.class 对于局部内部类(有名称的)来讲:他们对应的 .class 文件名称是:外部类类名$Number 内部类类名.class 其中的 Number 是 使用 该名称 的 内部类 在 外部类 出现的位置(第几个) 四、一个类可否获取到本身的内部类(静态内部类、成员内部类) GetInnerClass.java 五、一个内部类可否获取本身声明在哪一个类内部: GetOutterClass.java 六、建立内部类的实例 a>、局部内部类的实例,只能在当前的代码块内部使用, 好比 Human 类内部的 main 方法的 ON 类,则这个类只能在 main 方法内部使用 class ON{ // 局部内部类(Local Inner Class) } ON oo = new ON();// 建立局部内部类的实例 System.out.println(oo); b>、 建立静态内部类的实例: // 外部类.静态内部类 变量名 = new 外部类.静态内部类()Human.Country c = new Human.Country(); c>、建立实例内部类的实例: Human h = new Human();// 建立外部类的实例 外部类.实例内部类 变量名 = 外部类实例.new 实例内部类(); Human.Hand hand = h .new Hand(); 七、匿名内部类 有一个局部内部类,它连名字都没有,则它就是匿名内部类,可是它有对应的.class 文件 匿名内部类对应的.class 文件名 是外部类类名$数字.class a>、用匿名内部类实现接口: TestAnonymous1.java b>、用匿名内部类继承抽象类: TestAnonymous2.java c>、用匿名内部类继承普通的类: TestAnonymous3.java