Java基础7——抽象类、接口、内部类

1、抽象类

抽象类用于归并所有子类都必须有的属性和方法。抽象类可以包含常规类中的属性和非抽象方法,也可以包含抽象方法,如果没有抽象方法,只是不能用new操作符创建该类的实例。但是包含抽象方法的类必须声明为抽象类。

抽象方法归并了所有子类都必须有的行为的接口,只有方法原型,没有方法体实现。抽象方法是非静态的。

抽象不针对属性。

public abstract class <ClassName>{
	public abstract <returnType> <methodName>(...);
}

抽象类也有构造方法,初始化其中的数据域。用protected修饰,因为它只被子类使用。

抽象类不能使用new操作符创建实例。抽象类中的方法要被使用,必须由子类重写所有方法,使之不再为抽象类。

常规类的子类也可以是抽象的,子类也可以覆盖非抽象方法使其变为抽象。

抽象类可以声明引用,在多态中体现。

2、接口

接口是对外暴露的规则,只包含常量和抽象方法,没有构造方法。可以继承多个接口;成员有固定的修饰符,少写哪个会自动补;接口不可以创建对象。JDK8对接口增加了默认方法default public returnType methodName();使得接口中的方法有方法体,避免接口中增加方法时,它的实现类都要修改。

[修饰符] interface 接口名 [extends 父接口名1,2,…]{
	public static final XXX_YYY=[初值];//静态常量
	public abstract returnType methodName();//抽象方法
}

一个接口可以被子类实现,子类将接口及其父接口中所有方法覆盖后才可以实例化。通过对象名、类名、接口名均可以调用接口中的常量;支持多实现,假设有两个一样的方法名,一次就可以将它们都覆盖,但是如果方法名相同,返回类型不同是不可取的;一个类在继承父类时还可以同时实现接口,拓展功能;子类及其方法也必须全是public。

public class 类名称 [extends 父类名] implements 接口名1,2…{
	//实现接口和超接口所有方法
	//声明更多变量和方法
}

接口是程序的功能扩展,使类可以继承多个设计;实现不同类之间的常量共享;无论类之间有没有继承组合关系,功能相同就可以实现统一的对外服务接口,降低耦合性,最大限度地利用动态绑定,有利于模块化开发。

(1)Comparable接口

java.lang包中的Comparable接口定义了compareTo方法,用于比较对象。

public interface Comparable<E>{
 public int compareTo(E o);
}

这是一个泛型接口,实现该接口时,泛型类型E被替换为一种具体的类型,包括Byte、Short、Integer等数字、String字符串及Calendar、Date日期。当这个对象小于、等于或大于给定对象o时,分别返回负整数、0或正整数。如果对象是该接口类型的实例,就可用java.util.Arrays.sort(Object[])方法进行排序。也可以自定义对象类型实现该接口,之后用Arrays.sort进行排序。

public class ComparableRectangle extends Rectangle
	implements Comparable<ComparableRectangle>{
	public ComparableRectangle(double width,double height){
		super(width,height);
	}
	
	@Override
	public int compareTo(ComparableRectangle o){
		if(getArea()>o.getArea())
			return 1;
		else if(getArea()<o.getArea())
			return -1;
		else
			return 0;
	}
}

(2)Cloneable接口

public interface Cloneable{
}

java.lang包中的Cloneable接口是一个不包括常量和方法的标记接口,表示一个类拥有某些特定的属性。实现Cloneable接口的类标记为可克隆的,它的对象可以使用Object类中定义的clone方法,将原始对象的每个数据域复制给目标对象,对于基本类型复制它的值,对于对象复制该域的引用。

Java库中的许多类实现了该接口,如ArrayList、Date、Calendar,这些类的实例可以直接使用clone()。如果自定义实现该接口,这个类必须覆盖Object类中的clone()方法。将该方法覆盖为public。native表明这个方法不是用Java写的,但它是JVM针对自身平台实现的,因为Object类中针对自身平台实现的clone()方法完成了克隆对象的任务,所以简单调用父类方法即可。

//protected native Object clone() throws CloneNotSupportedException;
public class MyObject implements Cloneable{
	public Object clone() throws CloneNotSupportedException{
		return super.clone();
	}
}

抽象类和接口都是用来明确多个对象的共同特征的。一般来说,清晰描述父子关系强的“是一种”的关系应该用类建模,弱的“是一种”关系表明对象拥有某种属性可以用接口来建模。

3、内部类

内部类指将一个类定义在另一个类里面,通常当一个事物位于另外一个事物的内部时,该事物用内部类来描述。

class Outer{
	private int x=3;
		
	public void function(){
		new Inner().show();
	}
		
	private class Inner{
		void show(){
			System.out.println("show:"+x);
		}
	}
}

特征如下:

(1)内部类被编译为<外部类名>$<内部类名>.class。

(2)内部类可以直接访问外部类中的成员,包括私有,因为在内部类中有外部类的引用,格式<外部类名>.this。外部类要访问内部类,必须建立内部类对象。

(3)内部类定义在成员位置上可以用成员修饰符修饰。private将外部类在内部类中进行封装;static内部类只能访问外部类中的静态成员,如果类中数据都是静态,再将内部类设置为静态。当内部类定义了静态成员,该内部类必须是静态的。

(4)如果内部类非私有,也可以从其它外部类访问内部类。直接创建内部类对象,Outer.Inner in=new Outer().new Inner();访问静态内部类的非静态成员newOuter.Inner().function();访问静态内部类中的静态成员Outer.Inner.function();。当外部类的静态方法访问内部类时,内部类必须是静态的。

(5)通常,将内部类私有,需要提供内部类对象时,public void show(){ new Inner()},判断一些条件再暴露。

(6)内部类也可以定义在局部变量的位置上。还可以直接访问外部类中的成员,还持有外部类的引用;不能再被private和static修饰,因此内部类不能再有静态成员;创建对象才能运行;内部类只能访问被final修饰的局部变量。

匿名内部类

是内部类的简写格式。前提是内部类必须继承一个类或实现接口,匿名内部类是匿名子类对象。格式:new 父类或接口(){定义子类内容(复写)}。

注意:匿名内部类可以有名字,用其父类名声明,但只能访问父类中的方法(多态),此时可以访问多于一个方法;写匿名内部类时,其中的方法不要超过三个,否则阅读性非常差。

如果一个函数的形参是接口或抽象类,且方法数较少,可以考虑传入匿名内部类实参,简化代码。

abstract class AbsDemo{
	abstract void show();
}

class Outer{
	private int x=3;
		
	public void function(){
		new AbsDemo(){//匿名子类对象
			void show(){
				System.out.println("show:"+x);
			}
		}.show();
	}
}

public class OuterDemo {
	public static void main(String[] args) {
		new Outer().function();
	}
}

如果没有父类和接口,只是想利用一个方法,以Object为父类。

new Object(){
	public void function(){
		//省略
	}.function();
}

猜你喜欢

转载自blog.csdn.net/yaocong1993/article/details/80082184