甩手一张思维导图
1.内部类的概述
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
10.1创建内部类
- 代码实例:
public class Outer {
public Outer() {
System.out.println("实例化Outer.Outer");
}
class Inner {
public Inner() {
System.out.println("实例化我的时候,同时也实例化了外围类(Outer),Inner.Inner");
}
}
static class InnerStatic {
public InnerStatic() {
System.out.println("实例化我时,并没有实例化外围类InnerStatic.InnerStatic");
}
}
public Inner inners() {
return new Inner();
}
public static void main(String[] args) {
Outer outer = new Outer();
Inner inners = outer.inners();
Outer.InnerStatic innerStatic = new InnerStatic();
}
}
//打印的log日志
实例化Outer.Outer
实例化我的时候,同时也实例化了外围类(Outer),Inner.Inner
实例化我时,并没有实例化外围类InnerStatic.InnerStatic
Process finished with exit code 0
从main()方法中可以看到,从外部类(Outer)调用非静态的内部类时,必须通过外部类的引用来实例出Inner对象来。反之,静态内部类就不需要通过外部类的引用,直接就可以实例InnerStatic对象。 可以看出,静态内部类是相对于独立,非静态内部类依赖于外部类的引用。
从打印Log日志
非静态内部类,实例被创建的时候,它和外围实例之前的关联也随之被简历起来,而且,这种关联关系以后不能被修改。这种关联需要消耗非静态成员类实例的控件,并且增加了构造的时间开销。
静态成员类,它可以访问外围类的任何静态成员,包括哪些声明为私有的成员。静态成员类时外围类的一个静态成员,与其他的静态成员一样,也遵守同样的可访问性的规则。
10.2链接到外部类
interface Selector {
boolean end();
Object current();
void next();
}
public class Sequence {
private Object[] items;
private int next = 0;
public Sequence(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
//创建私有的非静态内部类,并且实现 Selector 接口
private class SequenceSelcetor implements Selector {
private int i = 0;
@Override
public boolean end() {
return i == items.length;//这句话表达内部类可以使用外围类的所有成员
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if (i < items.length)
i++;
}
}
public Selector selector() {
return new SequenceSelcetor();
}
public static void main(String[] args) {
//实例创建Sequence对象
Sequence sequence = new Sequence(10);
for (int i = 0; i < sequence.items.length; i++) {
sequence.add(Integer.toString(i));
}
//通过外围类的引用,实例创建成员类Selector对象
Selector selector = sequence.selector();
while (!selector.end()) {
System.out.print(selector.current() + " ");
selector.next();
}
}
}
其实看上面代码,主要讲:当生成一个内部了的对象时,此对象与制造它的外围类之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外内部类还拥有其外围类的所有元素的访问权。
10.3 使用.this与.new
package ten;
/**
* Created by Administrator on 2017/8/11.
*/
public class DotThis {
void f() {
System.out.println("f()");
}
public class Inner {
public DotThis dotThis() {
return DotThis.this;
}
public DotThis newDotThis() {
return new DotThis();
}
}
public Inner inner() {
return new Inner();
}
public static void main(String[] args) {
DotThis dotThis = new DotThis();
// DotThis.Inner dot = dotThis.new Inner();
System.out.println("dotThis = " + dotThis.toString());
DotThis.Inner dot = dotThis.inner();
System.out.println("dot = " + dot.toString());
DotThis dotThis1 = dot.dotThis();
System.out.println("dotThis1 = " + dotThis1.toString());
DotThis newDotThis = dot.newDotThis();
System.out.println("newDotThis = " + newDotThis.toString());
}
}
//Log日志:
dotThis = ten.DotThis@1540e19d
dot = ten.DotThis$Inner@677327b6
dotThis1 = ten.DotThis@1540e19d
newDotThis = ten.DotThis@14ae5a5
Process finished with exit code 0
从日志可以看出,首先27行实例创建DotThis()对象,30行通过外围类DotThis() 的引用,实例成员类Inner()的对象,32行通过成员类的引用来调用内部的doThis()方法,实例外围类DotThis()对象,34行同样是,通过成员类的引用调用内部的newDoThis()方法,实例一个新的外围DotThis()对象。
1.有时候可能想要告知某些其他对像,去创建其某个内部类的对象。要实现此目的,必须在new表达式中提供对其他外部类对象的引用,就像28行那样。
2.要想创建内部类的对象,必须通过外部类的对象来创建内部类对象,同时也解决了内部类名字作用域的问题。
3.在拥有外部类对象之前是不可能创建内部类对象的,这是因为内部类对象会暗暗地连接到创建它的外部类对象上。但是,如果创建的是嵌套类(静态内部类),那么就不需要对外部类对象的引用。
10.4内部类与向上转型
- 介绍:当内部了向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。(从实现了某个接口的独享,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的。)这好似因为此内部类——某个接口的实现——能够完全不可见,并且不肯用。所得到的只是指向基类或几口的引用。
/**
* Created by Administrator on 2017/8/14.
*/
interface Contents {
int value();
}
/**
* Created by Administrator on 2017/8/14.
*/
interface Destination {
String readLabel();
}
/**
* Created by Administrator on 2017/8/14.
* Parce4.class
*/
public class Parce4 {
//定义私有的Pcontents,并实现Contents接口,只有 Parce4能够访问该类
private class PContents implements Contents {
private int i = 11;
@Override
public int value() {
return i;
}
}
//定义受保护的PDestination,并实现Destination接口,只有在同一个包类可能访问,不局限于Parce4
protected class PDestination implements Destination {
private String label;
public PDestination(String label) {
this.label = label;
}
@Override
public String readLabel() {
return label;
}
}
//该方法可以返回 Destination对象,或者 Destination 子类
public Destination destination(String s) {
return new PDestination(s);
}
//该方法可以返回 Contents对象,或者 Contents 子类
public Contents contents() {
return new PContents();
}
}
/**
* Created by Administrator on 2017/8/14.
* TestParcel.class
*/
public class TestParcel {
public static void main(String[] args) {
Parce4 parce4 = new Parce4();
Contents contents = parce4.contents();
//向上转型,destination方法返回的是PDestination对象
Destination destination = parce4.destination("testLable");
}
}
10.5在方法和作用域内的内部类
- 一个定义在方法中的类
- 一个定义在作用域内的类,此作用域在方法的内部。
- 一个实现了将诶口的匿名类。
- 一个匿名类,它扩展了有非默认构造器的类。
- 一个匿名类,它执行字段初始化
- 一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
展示代码局部内部类实例:
/**
* Created by Administrator on 2017/8/14.
*/
public class Parcel5 {
public Destination destination(String s) {
int i = 0;//局部变量
//局部内部类
class PDestination implements Destination {
private String label;
public PDestination(String label) {
this.label = label;
}
@Override
public String readLabel() {
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel5 parce5 = new Parcel5();
Destination destination = parce5.destination("testmain");
}
}
展示作用域内嵌入类
public class Parcel5 {
private void internalTracking(boolean b) {
if (b) {
//该类嵌入在if语句的作用域内, 给我的感觉,很少用
class TrackingSlip {
private String id;
public TrackingSlip(String id) {
this.id = id;
}
String getSlip() {
return id;
}
}
}
}
}
10.6匿名内部类
匿名内部类
/**
* Created by Administrator on 2017/8/14.
*/
public class Parcel6 {
//1.第一种 匿名内部类
public Contents contents() {
return new Contents() {
private int i = 11;
@Override
public Object value() {
return i;
}
};
}
//2.第二种 创建一个实现Contents的匿名类的对象,通过new表达式返回的引用被自动想和桑转型为Contents的阴雨哦给你。
class MyContents implements Contents {
private int i = 12;
@Override
public Object value() {
return i;
}
}
public Contents contents1() {
return new MyContents();
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
Contents contents = parcel6.contents();
Object value = contents.value();
System.out.println("value = " + value);
Contents contents1 = parcel6.contents1();
}
}
10.6.1再访工厂方法
interface Service {
void method1();
void method2();
}
interface ServiceFactroy {
Service getService();
}
class Implementation1 implements Service {
public Implementation1() {
}
@Override
public void method1() {
System.out.println("Implementation1.method1");
}
@Override
public void method2() {
System.out.println("Implementation1.method2");
}
public static ServiceFactroy serviceFactroy = new ServiceFactroy() {
@Override
public Service getService() {
return new Implementation1();
}
};
}
class Implementation2 implements Service {
public Implementation2() {
}
@Override
public void method1() {
System.out.println("Implementation2.method1");
}
@Override
public void method2() {
System.out.println("Implementation2.method2");
}
public static ServiceFactroy serviceFactroy = new ServiceFactroy() {
@Override
public Service getService() {
return new Implementation2();
}
};
}
public class Factories {
public static void serviceConsumer(ServiceFactroy factroy) {
Service s = factroy.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(Implementation1.serviceFactroy);
serviceConsumer(Implementation2.serviceFactroy);
}
}
10.7嵌套类
- 所谓嵌套类,就是与外部类之间没有联系,并且嵌套类的声明是static。普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static就不是这样了。
- 要创建嵌套类的对象,并不需要其外围类的对象。
- 不能从嵌套类的对象中访问非静态的外围类对象。
嵌套类与普通的内部类还有一个区别。
- 普遍内部类的字段与方法,只能在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。
- 嵌套类可以包含所有这些东西:
/**
* Created by Administrator on 2017/8/14.
*/
public class Parcel11 {
//私有的ParcelContents嵌套类
private static class ParcelContents implements Contents {
private int i = 10;
@Override
public Object value() {
return i;
}
}
//私有的ParcelDestination嵌套类
protected static class ParcelDestination implements Destination {
private String label;
public ParcelDestination(String label) {
this.label = label;
}
@Override
public String readLabel() {
return label;
}
public static void f() {
}
static int x = 10;
static class AnotherLevel {
public static void f() {
}
static int x = 10;
}
}
public static Destination destination(String s) {
return new ParcelDestination(s);
}
public static Contents contents() {
return new ParcelContents();
}
public static void main(String[] args) {
//可以看到并没有通过外围类的引用来实例嵌套类,嵌套类是独立的。
Contents contents = contents();
Destination d = destination("tasmania");
}
}
10.7.1接口内部的类
/**
* Created by Administrator on 2017/8/9.
*/
public interface ClassInInterface {
void howdy();
//内部类实现外部接口,放到接口类中的任何类都自动地是public和static的
class TestClase implements ClassInInterface {
@Override
public void howdy() {
System.out.println("TestClase.howdy");
}
public static void testStatic(ClassInInterface classInInterface) {
System.out.println("TestClase.testStatic");
classInInterface.howdy();
}
public static void main(String[] args) {
new TestClase().howdy();
testStatic(new TestClase());
}
}
}
10.7.2从多层嵌套类中访问外部类的成员
一个内部类被嵌套多少层并不重要——它能透明地访问所有他所嵌入的外围类的所有成员
/**
* Created by Administrator on 2017/8/14.
*/
class MNA {
private void f() {
}
class A {
private void g() {
}
public class B {
void h() {
f();
g();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args) {
MNA mna = new MNA();
MNA.A mnaa = mna.new A();
MNA.A.B mnaab = mnaa.new B();
mnaab.h();
}
}
10.8为什么需要内部类
一般说来,内部类继承自某个类或实现某个接口,内部类的代码操作创建爱你它的外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
/**
* Created by Administrator on 2017/8/14.
*/
public class MultiInterfaces {
interface A {
}
interface B {
}
static class X implements A, B {
}
static class Y implements A {
B makeB() {
return new B() {
};
}
}
static void takesA(A a) {
}
static void takesB(B b) {
}
public static void main(String[] args) {
X x = new X();
Y y = new Y();
takesA(x);
takesA(y);
takesB(x);
takesB(y.makeB());
}
}