Java學習筆記九(abstract、抽象類、接口)

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");
			}
		}
	}

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章