abstract關鍵字的使用:
abstract:抽象的;
可以用來修飾的結構:類和方法;
abstract修飾類: 抽象類
此類不能進行實例化,但是類中一定要有構造器便於子類實例化時調用,這設計子類對象實例化的全過程;開發中都會提供抽象類的子類,通過子類對象實例化完成相關的操作。
abstract修飾方法: 抽象方法
抽象方法只有方法的聲明沒有方法體;
包含了抽象方法的類一定是一個抽象類,但是抽象類中可以沒有抽象方法;
若子類重寫了父類中所有的抽象方法,則此子類可以進行實例化;反之,如果沒有重寫父類中全部的抽象方法,則此子類也是一個抽象類,需要abstract進行修飾。
注意:abstract不能修飾私有的方法、static修飾的方法、final修飾的方法以及final修飾的類。(不能進行重寫則沒有意義,static修飾的方法不算重寫)。
public class AbstractTest {
public static void main(String[] args) {
//一旦Person類抽象了,就不可實例化
Person p1 = new Student();
p1.eat();
p1.breath();
}
}
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//不是抽象方法:
// public void eat(){
//
// }
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
@Override
public void breath() {
System.out.println("人應該呼吸");
}
}
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){
System.out.println("學生多喫有營養的食物");
}
// @Override
// public void breath() {
// System.out.println("學生應該呼吸新鮮的沒有霧霾的空氣");
// }
}
抽象類的匿名子類:
public class PersonTest {
public static void main(String[] args) {
method(new Student());//匿名對象
Worker worker = new Worker();
method1(worker);//非匿名的類非匿名的對象
method1(new Worker());//非匿名的類匿名的對象
System.out.println("********************");
//創建了一匿名子類的對象:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("喫東西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);
System.out.println("********************");
//創建匿名子類的匿名對象
method1(new Person(){
@Override
public void eat() {
System.out.println("喫好喫東西");
}
@Override
public void breath() {
System.out.println("好好呼吸新鮮空氣");
}
});
}
public static void method1(Person p){
p.eat();
p.breath();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
抽象類的應用:模板方法的設計模式
//抽象類的應用:模板方法的設計模式
public class TemplateMethodTest {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
BankTemplateMethod btm2 = new ManageMoney();
btm2.process();
}
}
abstract class BankTemplateMethod {
// 具體方法
public void takeNumber() {
System.out.println("取號排隊");
}
public abstract void transact(); // 辦理具體的業務 //鉤子方法
public void evaluate() {
System.out.println("反饋評分");
}
// 模板方法,把基本操作組合到一起,子類一般不能重寫
public final void process() {
this.takeNumber();
this.transact();// 像個鉤子,具體執行時,掛哪個子類,就執行哪個子類的實現代碼
this.evaluate();
}
}
class DrawMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要取款!!!");
}
}
class ManageMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要理財!我這裏有2000萬美元!!");
}
}
public class TemplateTest {
public static void main(String[] args) {
SubTemplate t = new SubTemplate();
t.spendTime();
}
}
abstract class Template{
//計算某段代碼執行所需要花費的時間
public void spendTime(){
long start = System.currentTimeMillis();
this.code();//不確定的部分、易變的部分
long end = System.currentTimeMillis();
System.out.println("花費的時間爲:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i = 2;i <= 1000;i++){
boolean isFlag = true;
for(int j = 2;j <= Math.sqrt(i);j++){
if(i % j == 0){
isFlag = false;
break;
}
}
if(isFlag){
System.out.println(i);
}
}
}
}
接口的使用:
1、接口使用interface來定義;
2、接口和類是並列的兩個結構;
3、如何定義接口:定義接口中的成員:
JDK7以前只能定義全局常量和抽象方法;
* 全局常量:public static final的;但是可以省略不寫;
*抽象方法:public abstract的;也可以省略 ;
JDK8:除了定義全局常量和抽象方法之外,還可以定義靜態方法和默認方法;
4、接口中不能定義構造器,說明接口不具備實例化的能力;
5、在開發中接口通過讓類去實現(implements)的方式來使用;如果類覆蓋了接口中所有的抽象方法,則這個類可以進行實例化;反之,如果類沒有覆蓋接口中所有的抽象方法,則這個類是一個抽象類。
6、一個類可以實現多個接口;(彌補了類的但繼承性)
- class AA extends BB implements CC,DD,EE
7、接口與接口之間可以繼承,而且可以多繼承;
- interface AA extends BB,CC
8、接口的使用體現了多態性,接口的使用實際上可以 看成是一種規範。
常見面試題:抽象類和接口的異同?
相同點:不能實例化;都可以包含抽象方法的。
不同點:
1)把抽象類和接口(java7,java8,java9)的定義、內部結構解釋說明
2)類:單繼承性 接口:多繼承
類與接口:多實現
public class InterfaceTest {
public static void main(String[] args) {
System.out.println(Flyable.MAX_SPEED);
System.out.println(Flyable.MIN_SPEED);
// Flyable.MIN_SPEED = 2;
Plane plane = new Plane();
plane.fly();
}
}
interface Flyable{
//全局常量
public static final int MAX_SPEED = 7900;//第一宇宙速度
int MIN_SPEED = 1;//省略了public static final
//抽象方法
public abstract void fly();
//省略了public abstract
void stop();
//Interfaces cannot have constructors
// public Flyable(){
//
// }
}
interface Attackable{
public abstract void attack();
}
class Plane implements Flyable{
@Override
public void fly() {
System.out.println("通過引擎起飛");
}
@Override
public void stop() {
System.out.println("駕駛員減速停止");
}
}
abstract class Kite implements Flyable{
@Override
public void fly() {
}
}
class Bullet extends Object implements Flyable,Attackable,CC{
@Override
public void attack() {
// TODO Auto-generated method stub
}
@Override
public void fly() {
// TODO Auto-generated method stub
}
@Override
public void stop() {
// TODO Auto-generated method stub
}
@Override
public void method1() {
// TODO Auto-generated method stub
}
@Override
public void method2() {
// TODO Auto-generated method stub
}
}
//************************************
interface AA{
void method1();
}
interface BB{
void method2();
}
interface CC extends AA,BB{
}
如果一個類繼承的類和實現的接口中定義了同名的屬性,則應該通過super來指定類中的屬性,用“接口。xx”來指定接口中的全局常量;
interface A {
int x = 0;// 省略了public static final
} // x 爲全局常量
class B {
int x = 1;
}
class C extends B implements A {
public void pX() {
//編譯不通過。因爲x是不明確的
// System.out.println(x);
System.out.println(super.x);//1
System.out.println(A.x);//0
}
public static void main(String[] args) {
new C().pX();
}
}
接口的應用:代理模式
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
// server.browse();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理類
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真實的服務器訪問網絡");
}
}
//代理類
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("聯網之前的檢查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
public class StaticProxyTest {
public static void main(String[] args) {
Proxy s = new Proxy(new RealStar());
s.confer();
s.signContract();
s.bookTicket();
s.sing();
s.collectMoney();
}
}
interface Star {
void confer();// 面談
void signContract();// 籤合同
void bookTicket();// 訂票
void sing();// 唱歌
void collectMoney();// 收錢
}
//被代理類
class RealStar implements Star {
public void confer() {
}
public void signContract() {
}
public void bookTicket() {
}
public void sing() {
System.out.println("明星:歌唱~~~");
}
public void collectMoney() {
}
}
//代理類
class Proxy implements Star {
private Star real;
public Proxy(Star real) {
this.real = real;
}
public void confer() {
System.out.println("經紀人面談");
}
public void signContract() {
System.out.println("經紀人籤合同");
}
public void bookTicket() {
System.out.println("經紀人訂票");
}
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("經紀人收錢");
}
}
接口的使用:
1、接口的使用也滿足多態性;
2、接口,實際上就是定義了一種規範;
3、開發中體驗面向接口編程;
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.創建了接口的非匿名實現類的非匿名對象
Flash flash = new Flash();
com.transferData(flash);
//2. 創建了接口的非匿名實現類的匿名對象
com.transferData(new Printer());
//3. 創建了接口的匿名實現類的非匿名對象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手機開始工作");
}
@Override
public void stop() {
System.out.println("手機結束工作");
}
};
com.transferData(phone);
//4. 創建了接口的匿名實現類的匿名對象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3開始工作");
}
@Override
public void stop() {
System.out.println("mp3結束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("具體傳輸數據的細節");
usb.stop();
}
}
interface USB{
//常量:定義了長、寬、最大最小的傳輸速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盤開啓工作");
}
@Override
public void stop() {
System.out.println("U盤結束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印機開啓工作");
}
@Override
public void stop() {
System.out.println("打印機結束工作");
}
}
JDK8允許接口定義默認方法和靜態方法:
public interface CompareA{
// 靜態方法
public static void method1(){
System.out.println("Method1");
}
//默認方法
public default void method2(){
System.out.println("method2");
}
default void method3(){ //這裏只是省略了public,
//並不是說權限變成了缺省
//接口中可以省略
System.out.println("method3");
}
}
靜態方法和默認方法的使用:
1、接口中的靜態方法只能通過接口來進行調用;
2、接口中的默認方法可以使用實現類的對象進行調用,如果實現類重寫了接口中的方法,則調用的是實現類中重寫的方法;
3、如果實現類(子類)繼承的父類和實現的接口中,聲明瞭同名同參數的默認方法,那麼子類在沒有重寫此方法的情況下,默認調用的是父類中同名同參數的方法;(類優先原則)
4、如果實現類實現了多個接口,並且接口中定義了同名同參數的方法,那麼實現類在沒有重寫此方法的情況下,實現類無法進行調用;報錯:接口衝突;
5、如何在子類(實現類)中調用父類或接口中被重寫的方法;
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// s.method1();
// SubClass.method1();
//知識點1:接口中定義的靜態方法,只能通過接口來調用。
CompareA.method1();
//知識點2:通過實現類的對象,可以調用接口中的默認方法。
//如果實現類重寫了接口中的默認方法,調用時,仍然調用的是重寫以後的方法
s.method2();
//知識點3:如果子類(或實現類)繼承的父類和實現的接口中聲明瞭同名同參數的默認方法,
//那麼子類在沒有重寫此方法的情況下,默認調用的是父類中的同名同參數的方法。-->類優先原則
//知識點4:如果實現類實現了多個接口,而這多個接口中定義了同名同參數的默認方法,
//那麼在實現類沒有重寫此方法的情況下,報錯。-->接口衝突。
//這就需要我們必須在實現類中重寫此方法
s.method3();
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("SubClass:上海");
}
public void method3(){
System.out.println("SubClass:深圳");
}
//知識點5:如何在子類(或實現類)的方法中調用父類、接口中被重寫的方法
public void myMethod(){
method3();//調用自己定義的重寫的方法
super.method3();//調用的是父類中聲明的
//調用接口中的默認方法
CompareA.super.method3();//當成是一個規定就行;
CompareB.super.method3();//就理解爲實現接口的。。。
}
}
類的成員之內部類:
1、Java中允許將一個類A聲明在一個類B中,則類A稱爲內部類,類B稱爲外部類;
2、內部類可以分爲:
成員內部類(靜態的和非靜態的)VS局部內部類(方法、代碼塊、構造器內);
3、成員內部類:
一方面做爲類的成員:
①可以使用四種權限修飾符;
②可以調用外部類的結構;
③可以使用static進行修飾;
另一方面作爲一個類:
①可以使用final、abstract進行修飾;
②類內可以定義屬性、方法、構造器;
4、內部類主要關注以下三個問題:
①如何實例化內部類的對象;
②如何在內部類中區分調用外部類的結構;
③開發中局部內部類的使用;
public class InnerClassTest {
public static void main(String[] args) {
//創建Dog實例(靜態的成員內部類):
Person.Dog dog = new Person.Dog();
dog.show();
//創建Bird實例(非靜態的成員內部類):
// Person.Bird bird = new Person.Bird();//錯誤的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println();
bird.display("黃鸝");
}
}
class Person{
String name = "小明";
int age;
public void eat(){
System.out.println("人:喫飯");
}
//靜態成員內部類
static class Dog{
String name;
int age;
public void show(){
System.out.println("卡拉是條狗");
// eat();
}
}
//非靜態成員內部類
class Bird{
String name = "杜鵑";
public Bird(){
}
public void sing(){
System.out.println("我是一隻小小鳥");
Person.this.eat();//調用外部類的非靜態屬性
eat();
System.out.println(age);
}
public void display(String name){
System.out.println(name);//方法的形參
System.out.println(this.name);//內部類的屬性
System.out.println(Person.this.name);//外部類的屬性
}
}
public void method(){
//局部內部類
class AA{
}
}
{
//局部內部類
class BB{
}
}
public Person(){
//局部內部類
class CC{
}
}
}
public class InnerClassTest1 {
//開發中很少見
public void method(){
//局部內部類
class AA{
}
}
//返回一個實現了Comparable接口的類的對象
public Comparable getComparable(){
//創建一個實現了Comparable接口的類:局部內部類
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
}
局部內部類的使用還應注意:
在局部內部類的方法(show)如果調用外部類聲明方法(method)中的局部變量(num),則要求則局部變量聲明爲final的;
JDK7及以前,需要顯示聲明final
JDK8及以後可以省略final;
public class InnerClassTest{
public void method(){
num = 10;
class AA{
public void show(){
// num = 20 //final的num,不可以在進行賦值;
System.out.println("num");
}
}
}
}