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允许接口定义默认方法和静态方法:

扫描二维码关注公众号,回复: 11112976 查看本文章
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");
			}
		}
	}

}
发布了28 篇原创文章 · 获赞 23 · 访问量 6620

猜你喜欢

转载自blog.csdn.net/ssnszds/article/details/104576105