1、接口
interface用来定义接口,接口里通常是定义一组公用方法,所以接口中方法和成员只能是public,而且可以省略不写。
接口里包含抽象方法(可以省略不写public abstract)、默认方法(使用default声明)、类方法(静态成员函数)。
接口里不能包含构造函数和初始化定义块,可以包含静态常量成员(只能是public static final类型,且可以省略不写)、内部类(包括内部接口、内部枚举)。
接口也是使用extends继承,而且只能继承自接口,不能继承自类。与类不同的是,接口可以多继承。
与类相似,一个接口中最多只能包含一个public接口,而且源文件名应该与public接口名相同。
接口中的抽象方法通过类来实现,使用implements,一个类可以实现多个接口。
类必须实现接口中所有的抽象方法,否则这个类应该被声明为抽象类,接口的实现可以看做是一种特殊的继承。
接口不能被实例化对象,但可以定义接口引用变量来指向实现了接口的类的对象(类似父类引用指向子类对象),接口引用变量可以赋给Object类型引用变量(java中所有类都是Object的子类)。
package lee;
interface interA
{
int NUM = 10; //常量成员
void func(); //抽象方法
default void display() //默认方法
{
System.out.println("display");
}
}
interface interB
{
static String func() //类方法
{
return "接口类interB的静态方法";
}
}
interface subInter extends interA, interB //多继承
{
}
public class Output implements interA, interB
{
public void func() //实现接口interA的抽象方法
{
int num = NUM; //引用接口的成员
display(); //调用接口的默认方法
}
public static void main(String[] args)
{
interA in = new Output(); //接口引用变量可以指向实现了接口的类的对象
in.display(); //调用接口的默认方法
in.func(); //调用类中实现的接口方法
Object o = in; //接口引用变量可以赋给Object类型引用变量
}
}
简单工厂模式:
比如对于Computer类,它需要组合一个输出设备Printer,但我们不是直接在Printer中定义输出的方法,而是将输出方法放在接口Output中,让Printer从Output继承,Computer从工厂类OutputFactory中获取输出设备。这样当我们需要更换输出设备为BetterPrinter的时候(BetterPrinter也是继承自Output),可以直接更改OutputFactory中生产输出设备的方法getOutput()为产生BetterPrinter对象就行。
如果我们是直接在Printer中定义输出的方法,Computer直接包含Printer对象的话,当我们需要修改Computer为BetterPrinter的话,如果Computer中有多处使用Printer的地方的话改起来就会很麻烦。
/**************Output.java**************/
package lee;
public interface Output
{
void out();
void getData();
default void func()
{
System.out.println("func");
}
}
/**************Printer.java**************/
package lee;
abstract class Device
{
public abstract String getDeviceName();
}
public class Printer extends Device implements Output
{
public void out()
{
//...
}
public void getData()
{
//...
}
public String getDeviceName()
{
return "Printer";
}
}
/**************OutputFactory.java**************/
package lee;
public class OutputFactory
{
public static Output getOutput()
{
return new Printer();
}
}
/**************Computer.java**************/
package lee;
public class Computer
{
private Output out;
public Computer()
{
out = OutputFactory.getOutput();
}
public void scan()
{
out.getData();
}
public void print()
{
out.out();
}
}
命令模式:
比如对于数据的处理操作,被调用者只提供一个接口规范,而具体操作由调用者来指定,类似于调用者向被调用者发送指定命令一样:
/***************Command.java**************/
public interface Command
{
void process(int[] target);
}
/***************CommandPerform.java**************/
public class CommandPerform
{
private int[] ary;
CommandPerform(int[] ary)
{
this.ary = ary;
}
public void process(Command cmd)
{
cmd.process(ary);
}
}
/***************Foo.java**************/
class printCommand implements Command
{
public void process(int[] target)
{
for(int item:target)
{
System.out.println(item);
}
}
}
class sumCommand implements Command
{
public void process(int [] target)
{
int sum = 0;
for(int item:target)
{
sum += item;
}
System.out.println(sum);
}
}
public class Foo
{
void func(int num)
{
num = 0;
}
public static void main(String [] args)
{
int[] ary = {3, 5, 1, 4};
CommandPerform ct = new CommandPerform(ary);
ct.process(new printCommand());
ct.process(new sumCommand());
}
}
2、内部类
内部类就是在类的内部定义的类,相当于类的成员,所以除了public还可以使用protected、private、static修饰符来声明它。
内部类可以直接访问外部类的私有数据,但外部类不能直接访问内部类的私有数据(可以通过类名或对象来访问)。
根据静态方法中不能访问非静态成员的规则,外部类的静态方法不能访问非静态内部类,静态内部类不能访问外部类的非静态成员。
与普通类不同的一点:非静态内部类不能拥有静态成员。
接口里也可以定义内部类,而且只能是public static类型,可以省略不写。接口里也可以定义内部接口,但意义不大。
class Test
{
private int id = 10;
public class Inner
{
private int id = 0;
void print()
{
System.out.println(id); //内部类中可以直接访问外部类的private成员
id = Test.this.id; //使用“外部类名.this.成员变量名”来引用外部类中同名成员变量。
}
}
public static class InnerS
{
private String str; //静态内部类中可以包含非静态成员
private static int id = 0;
void display()
{
System.out.println(str);
}
}
void func()
{
System.out.println(new InnerS().str); //通过对象访问内部类的私有成员
int i = InnerS.id; //通过类名访问内部类的私有静态成员
}
}
class Foo //外部类以外的类定义非静态内部类类型的对象
{
void func()
{
Test.Inner in = new Test().new Inner(); //创建非静态内部类对象时需要外部类对象存在
Test.InnerS is = new Test.InnerS(); //创建静态内部类对象时不需要外部类对象存在
}
}
class SubInner extends Test.Inner //从非静态内部类继承的子类的构造函数调用时必须存在一个外部类的对象
{
SubInner(Test t)
{
t.super(); //父类Inner的构造函数使用外部类对象t来调用,通过调用super()
}
}
3、局部内部类和匿名内部类
除了成员内部类,还可以在方法中定义内部类,这就是局部内部类,局部内部类不能使用public、private等访问控制符以及static修饰符。局部内部类实际中很少会使用,而是使用匿名内部类。
如果局部内部类或匿名内部类中引用了方法的局部变量,那么这个变量就自动成为了final类型。
匿名内部类适合只使用这个类来定义一次对象的情况,其定义格式如下,匿名内部类必须继承一个父类或实现一个接口,且最多只能继承一个父类或实现一个接口。匿名内部类不能是抽象类,因为匿名内部类定义时会直接创建对象,匿名内部类中必须实现接口或父类的抽象方法,也可以重写父类的方法。匿名内部类不能定义构造器,但可以定义初始化块,通过初始化块来完成初始化。
new 接口() | 父类(实参列表)
{
//类体
}
匿名内部类经常用来创建某个接口类型的对象,如下所示:
interface Product
{
public String getName();
}
class Bar
{
public void test(Product p)
{
p.getName();
}
public void func1() //使用普通内部类
{
int n = 0;
class GoodProduct implements Product
{
n = 1; //错误!n自动成为final类型
public String getName()
{
return "name";
}
}
test(new GoodProduct());
}
public void func2() //使用匿名内部类
{
int n = 0;
test(new Product()
{
public String getName()
{
n = 1; //错误!n自动成为final类型
return "name";
}
});
}
}