Java学习笔记一面向对象接口

定义接口

接口是从多个相似类中抽象出来的规范,接口不提供任何实现。从某个角度看,接口可被当成一个特殊类,因此Jva源文件里最多只能有一个public接口,如果一个Java源文件里定义了一个public接口,则该源文件的主文件名必须与该接口名相同。接口完全支持多继承,子接口扩展某个父接口,将会获得父接口里定义的所以抽象方法、常量。

[修饰符] interface 接口名 extends 父接口1, 父接口2...
{
	零个到多个常量定义...
	零个到多个抽象方法定义...
	零个到多个私有方法、默认方法或类方法定义...
	零个到多个内部类、接口、枚举定义...	
}

修饰符可以是public或者省略,如果省略了public访问控制符,则默认采用包权限访问控制符,即只有在相同包结构下才可以访问该接口。一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。
由于接口定义的是一种规范,因此接口里不能包含构造器和初始化块定义。接口里可以包含成员变量(只能是静态常量)、方法(只能是抽象实例方法、类方法、默认方法或私有方法)、内部类(包括内部接口、枚举)。

接口中定义成员变量时,不管是否使用public static final修饰符,接口里的成员变量总是使用这三个修饰符来修饰。而且接口里没有构造器和初始化块,因此接口里定义的成员变量只能在定义时指定默认值。

// 系统自动为接口里定义的成员变量增加public static final修饰符
// 可以省略访问控制修饰符,因为接口里的常量只能是public
int MAX_SIZE = 50;
public static final int MAX_SIZE = 50; 

如果不是定义默认方法、类方法或私有方法,系统将自动为普通方法增加abstract修饰符;定义接口里的普通方法时不管是否使用public abstract修饰符,接口里的普通方法总是使用public abstract修饰符。接口里的普通方法不能有方法实现(方法体)。

Java 9为接口增加了一种新的私有方法,私有方法的作用就是作为工具方法,为接口中的默认方法或类方法提供支持。私有方法可以拥有方法体,但私有方法不能使用default修饰。私有方法可以使用static修饰,也就是说,私有方法既可以是类方法,也可以是实例方法。private void test() {} 私有成员方法 或 private static void test() {} 私有类方法 必须有方法体。

在接口中定义默认方法,需要用default修饰,不能使用static修饰,且总是以public修饰,如果没有指定,系统会自动添加public default void test() {} 必须有方法体。

类方法使用static修饰,不能使用default修饰,无论程序是否指定,类方法总是public修饰,如果开发者没有指定public,系统会自动为类方法添加public修饰符,必须有方法体。

接口里定义的内部类、内部接口、内部枚举默认采用public static两个修饰符,不管定义时是否指定这两个修饰符,系统都会自动使用public static对它们进行修饰。

public interface Output
{
	//接口里定义的成员变量只能是常量
	int MAX_CACHE_LINE = 50;
	//接口里定义的普通方法只能是public的抽象方法
	void out();
	void getData(String msg);
	//在接口中定义默认方法,需要使用default修饰
	default void print(String.. msg)
	{
		for(String msg:msgs)
			System.out.println(msg);
	}
	//在接口中定义默认方法,需要使用default修饰
	default void test()
	{
		System.out.println("默认的test方法");
	}
	//在接口中定义类方法,需要使用static修饰
	static String staticTest()
	{
		return "接口里的类方法";
	}
	//定义私有方法
	private void foo()
	{
		System.out.println("foo私有方法");
	}
	//定义私有静态方法
	private static void bar()
	{
		System.out.println("bar私有静态方法");
	}
}

接口里定义内部类默认使用public static修饰,也就是说接口内部类只能是静态内部类。如果为接口内部类指定访问控制符,则只能指定public访问控制符;如果定义接口内部类时省略访问控制符,则该内部类默认是public访问控制权限。

接口里可以定义内部接口,系统默认添加public static修饰符。如果定义接口里的内部接口时指定访问控制符,则只能使用public修饰符。

使用接口

接口不能用于创建实例,但接口可以用于声明引用类型变量。当使用接口来声明引用类型变量时,这个引用类型变量必须引用到其实现类的对象。一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法;否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。

[修饰符] class 类名 extends 父类 implements 接口1, 接口2...
{
	类体
}

实现接口方法时,必须使用public访问控制修饰符,因为接口里的方法都是public的,而子类(相当于实现类)重写父类方法时访问权限只能更大或者相等,所以实现类实现接口里的方法时只能使用public访问权限。

//定义一个Product接口
interface Product
{
	int getProduceTime();
}
//让Printer类实现Output和Product接口
public class Printer implement Output, Product
{
	private String[] printData = new String[MAX_CACHE_LINE]; 
	//用以记录当前需打印的作业数
	private int dataNum = 0;
	//接口Output的抽象方法的实现
	public void out()
	{
		//只要还有作业,就继续打印
		System.out.println("打印机打印:"+printData[0]);
		//把作业队列整体前移一位,并将剩下的作业数减一
		System.arraycopy(printData,1,printData,0--dataNum);
	}
	public void getData(String msg)
	{
		if(dataNum >= MAX_CACHE_LINE)
			System.out.println("输出队列已满");
		else
			printData[dataNum++] = msg;
	}
	//接口Product的抽象方法的实现
	public int getProduceTime() { return 45; }
	public static void main(String[] args)
	{
		Output o = new Printer();
		o.getData("helloworld");
		o.getData("hello");
		o.out();
		o.getData("world");
		o.getData("wow");
		o.out();
		o.print("孙","悟","空");
		o.test();
		Product p = new Printer();
		System.out.println(p.getProduceTime());
		//所有接口类型的引用变量都可直接赋给Object类型的变量
		Object obj = p;
	}
}

接口不能显式继承任何类,但所有接口类型的引用变量都可以直接赋给Object类型的引用变量。上面程序把Product类型的变量直接赋给Object类型变量,这是利用向上转型来实现的。因为编译器知道任何Java对象都必须是Object或其子类的实例,Product类型的对象也不例外(它必须是Product接口实现类的对象,该实现类肯定是Object的显式或隐式子类)。

面向接口编程

简单工厂模式

Computer类可以组合一个Output,可以用不同类来替换,如Printer和BetterPrinter,将输出设备分离,只和Output接口耦合。

public class Computer
{
	private Output out;
	public Computer(Output out)
	{
		this.out = out;
	}
	//模拟获取字符串输入的方法
	public void keyIn(String msg)
	{
		out.getData(msg);
	}
	//模拟打印的方法
	public void print()
	{
		out.out();
	}
}

Computer类不再负责创建Output对象,这里提供一个工厂类来生成Output对象。

public class OutputFactory
{
	public Output getOutput()
	{
		return new Printer();
	}
	public static void main(String[] args)
	{
		OutputFactory of = new OutputFactory();
		Computer c = new Computer(of.getOutput());
		c.keyIn("Hello");
		c.keyIn("World");
		c.print();
	}
}

命令模式

某个方法需要完成某个行为,但这个行为具体实现无法确定,必须等到执行该方法时才能确定。对于这样的需要,必须把处理行为作为参数传入该方法。考虑使用一个Command接口来定义一个方法,用这个方法来封装处理行为。

public interface Command
{
	//接口里定义的process方法用于封装处理行为
	void process(int[] target);
}
// 两种实现
public interface PrintCommand implements Command
{
	void process(int[] target){
		for(int tmp:target)
			System.out.println("迭代输出目标数组的元素:"+tmp);
	}
}
public interface AddCommand implements Command
{
	void process(int[] target){
		int sum = 0;
		for(int tmp:target)
			sum += tmp;
		System.out.println("迭代输出目标数组的元素:"+sum);
	}
}

通过Command接口,实现让ProcessArray类和具体处理行为分离。

public class ProcessArray
{
	public void process(int[] target, Command cmd)
	{
		cmd.process(target);
	}
}
public class CommandTest
{
	public static void main(String[] args)
	{
		ProcessArray pa = new ProcessArray();
		int[] target = {3, -4, 6, 4};
		pa.process(target, new PrintCommand());
		pa.process(target, new AddCommand());
	}
}
发布了134 篇原创文章 · 获赞 141 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asmartkiller/article/details/104898145