1、抽象类和抽象方法
如果我们只提供接口,但没有具体的实现内容,创建这个对象是没有什么意义的,而且我们可能还想要阻止使用者这么做。通过让这个对象的所有方法报错可以实现阻止创建这个对象的目的。但是这样做会将错误信息延迟到运行时才获得,并且要在客户端进行可靠、详尽的测试。所以最好在编译时捕获这些问题。也就是尽可能不创建无内容的接口或者说对象。
为此,Java提供了一个叫做抽象方法的机制,这种方法是不完整的,仅有声明而没有方法体。语法:
abstract void f();
包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的(否则,编译器会报错)
如果一个抽象类不完整,那么当我们视图产生该类的对象时,编译器会由于为抽象类创建对象不完全而报错。这样,编译器会确保抽象类的纯粹性,我们不必担心误用。
如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供方法定义。如果不这样做(可以选择不做),那么导出类便也是抽象类,且编译器将会强制我们用abstrace关键字来限定这个类。
我们也可能会创建一个没有任何抽象方法的抽象类。这个类包含任何abstract方法都显得没有实际意义,而且我也想要阻止产生这个类的任何对象,那么这样做就有用了。
2、接口
interface关键字使抽象的概念更向前迈进了一步。abstract关键字允许人们在类中创建一个或多个没有任何定义的方法——提供了接口部分,但是没有提供任何相应的具体实现,这些实现由此类的继承者创建的。interface这个关键字产生一个完全抽象的类,根本没有提供任何具体的实现。它允许创建者确定方法名、参数列表和返回类型,但是没有任何方法体。接口只提供了形式,而未提供任何具体实现。
一个接口表示:“所有实现了该特定接口的类看起来都像这样”。因此,任何使用某特定接口的代码都知道可以调用该接口的哪些方法,而且仅需要知道这些。因此,接口被用来建立类与类之间的协议。(某些面向对象编程语言使用protocol关键词来完成)
interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性。
如果不再interface前添加public关键字,则它只有包访问权限,只能在同一个包内可用。接口也可以包含域,但是这些域隐式地是static和final的。
3、策略设计模式
调用方中的一个方法可以接受一个基类,然和根据这个基类的超类具有不同的行为。也就是创建一个能够根据锁传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式。
4、使用接口的核心原因
为了能够向上转型为多个基类型(以及由此而带来的灵活性)。然而,使用接口的第二个原因却是与使用抽象基类相同:防止客户端程序员创建该类的对象,并确保这仅仅是建立一个接口。这就会有一个问题:我们到底应该使用接口还是抽象类?如果要创建不带任何方法定义和成员变量的基类,那么应该选择接口而不是抽象类。事实上,如果知道某事物应该成为一个基类,那么第一选择应该是使它成为一个接口。
5、嵌套接口
接口可以嵌套在类或其他接口中
接口也可以被实现为private,可以被实现为public,但是只能被其自身所使用。也就是说实现一个private接口只是一种方式,它可以强制该接口中的方法定义不要添加任何类型信息(也就是说,不允许向上转型)。
接口彼此之间也可以嵌套。但是所有的接口元素都必须是public,而且在另一个接口中的接口自动是public 的,而不能声明为private。
当实现某个接口时,并不需要实现嵌套在其内部的任何接口。而且,private不能在定义它的类之外被实现。
6、接口和工厂
接口是实现多重继承的途径,而生成遵循某个接口的典型方式就是工厂方法设计模式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现。
7、内部类
可以将一个类的定义放在另一个类的定义内部,就是内部类。
为什么内部类自动拥有对外围类所有成员的访问权?
当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。然后在你访问此外围类的成员时,就是用那个引用来选择外围类的成员。编译器会帮我们处理所有的细节。内部类的对只能在其外围类的对象相关联的情况下才能被创建(内部类非static类时)。构建内部类对象时,需要一个执行其外围类对象的引用,如果编译器访问不到这个引用就会报错。
public Selector selector() {
return new InnerSelector();
}
会自动被编译成
public Selector selector() {
return new Inner.InnerSelector();
}
8、在方法和作用域内的内部类
8.1、为什么在一个方法里面或者在任意的作用域内定义内部类:
8.1.1、实现了某类型的接口,于是可以创建并返回对其的引用。
8.1.2、要解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。
8.2、在方法的作用于内的(而不是在其他类的作用于内)创建一个完整的类。叫做局部内部类
PDestination是destination()方法的一部分,而不是PartInner的一部分。所以在destination()之外不能访问PDestination。return语句进行了向上转型——返回的是destination的引用,为PDestination的基类。
9、嵌套类
如果不需要内部类对象与其外围类对象之间的关系,那么可以将内部类声明为static。这通常被称为嵌套类。普通的内部类镀锡隐式地保存了一个引用,指向创建它的外围类对象。当内部类时staic时,嵌套类意味着:
要创建嵌套类的对象,并不需要其外围类的对象。
不能从嵌套类的对象中访问非静态的外围类对象。
普通的内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和staitic字段,也不能包含嵌套类。但是嵌套类可以包含它们。
在一个普通的(非staitic)内部类中,通过一个特殊的this引用可以连接到其外围类对象。嵌套类没有这个特殊的this引用,这使得它类似一个static方法。
10、接口内部的类
正常情况下,不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类都自动地是public和static的。因为类时static,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则,甚至可以在内部类中实现其外围接口。
如果想要创建某些公共代码,使得它们可以被某个接口的所有不同实现所公用,那么使用接口内部的嵌套类就很方便。也可以用嵌套类来放测试代码。
工厂模式 只是根据Factory返回不同的对象,不需要自己加配置
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Imple1 implements Service {
@Override
public void method1() {
System.out.println("Imple1method1");
}
@Override
public void method2() {
System.out.println("Imple1method1");
}
}
class ImpleFact1 implements ServiceFactory {
@Override
public Service getService() {
return new Imple1();
}
}
class Imple2 implements Service {
@Override
public void method1() {
System.out.println("Imple2method1");
}
@Override
public void method2() {
System.out.println("Imple2method1");
}
}
class ImpleFact2 implements ServiceFactory {
@Override
public Service getService() {
return new Imple2();
}
}
public class Factories {
static void serviceConsu(ServiceFactory fact) {
Service service = fact.getService();
service.method1();
service.method2();
}
public static void main(String[] args) {
serviceConsu(new ImpleFact1());
serviceConsu(new ImpleFact2());
}
}
内部类对外围类的所有成员有访问权
public class Inner {
private Object[] items;
private int next = 0;
public Inner(int size) {
this.items = new Object[size];
}
public void add(Object x) {
if (this.next < this.items.length) {
this.items[this.next++] = x;
}
}
public Selector selector() {
return new Inner.InnerSelector();
}
public static void main(String[] args) {
Inner inner = new Inner(10);
for(int i = 0; i < 10; ++i) {
inner.add(Integer.toString(i));
}
Selector selector = inner.selector();
while(!selector.end()) {
System.out.println(selector.current() + "");
selector.next();
}
}
private class InnerSelector implements Selector {
private int i;
private InnerSelector() {
this.i = 0;
}
public boolean end() {
return this.i == Inner.this.items.length;
}
public Object current() {
return Inner.this.items[this.i];
}
public void next() {
if (this.i < Inner.this.items.length) {
++this.i;
}
}
}
}
局部内部类
interface Destination {
String readLabel();
}
public class PartInner {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String label){
this.label = label;
}
@Override
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args){
PartInner partInner = new PartInner();
Destination eeeee = partInner.destination("eeeee");
System.out.println(eeeee.readLabel());
}
}
接口内部类
interface a {
void run();
class b implements a {
@Override
public void run() {
System.out.println("hhh");
}
public static void main(String[] args) {
new b().run();
}
}
}