Class A{
Class B{}
}
B类就是A类的一个内部类。
而当需要new一个B类,就是需要A.B b = A.new B()。
链接到外部类
也就是说书中的例子比较详细,这里只是举个例子
Class A{
private String s;
Class B{
pritln(s);
public A getA(){
return A.this;
}
}
}
用private修饰的成员,内部类B是可以直接进行调用的,也就是说A这个外围类的所有成员,内部类B都是可以访问的。内部类B是可以获取到外围类A的所有成员(变量,方法)。然后由开头A.B b = A.new B()获取内部类B的对象,通过A.B这样关联了起来,也就是说编译器创建这个内部类对象的时候,通过A来关联,也就是说当我们创建了b这个对象的时候已经得到了A的引用。
.this和.new
开头使用的A.B b = A.new B()就是.new的用法,可以获取到内部类B的对象。而使用.this就是内部类用来获取外围类对象,也就是getA()方法中写的这样。
向上转型
public interface C{}
public Class A{
private String s;_
public B getB(){return new B();}
private Class B implement C{
pritln(s);
}
}
这里是可以C c = A.getB()也就是可以向上转型,这跟我们正常的使用方式没有说明区别。
差别在于,正常我们定义类,只能使用public或者是default进行修饰,这样我们就可以通过A a = new A()这个时候A类对于所有人都是可见的(也就是可以直接new出来),但是在内部类中是可以进行private修饰内部类B的,而这样,就没有办法像上面这样A.B b = A.new B()通过.new直接创建对象了,这个时候内部类对于我们来说完全不可见的(也就是无法new出来)。
并且也就是B去实现了C接口,然后他的实现方法我们是没办法直接new出来的,这样就使得B的具体实现隐藏起来了。
隐藏实现细节,我们已经知道了。但是什么叫完全阻止任何依赖于类型的编码,而这个时候我们要知道的是,内部类也是可以被其他类继承。但是需要在构造器中调用,外围类.super()默认构造器或者是自定义的构造器才能编译通过。
class WithInner{
class Inner{
}
}
class test3 extends WithInner.Inner{
test3(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner wi = new WithInner();
test3 t3 = new test3(wi);
}
}
https://blog.csdn.net/yuwenhao07/article/details/53638954 借鉴这里
这样是可以但是,这里我们看到是没有使用private修饰Inner这个时候就可以依赖于Inner来创建Test3这个类,这个时候当我们将Inner用private修饰之后,编译器是阻止我们继承Inner这个内部类的,这个时候就“完全阻止任何依赖于类型的编码”。我的理解是这样的。
方法和作用域内的内部类(局部内部类)
public class Parcel6 {
private void internalTracking(boolean b) {
if(b) {
class TrackingSlip {
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip() { return id; }
}
TrackingSlip ts = new TrackingSlip("slip");
String s = ts.getSlip();
}
// Can't use it here! Out of scope:
//! TrackingSlip ts = new TrackingSlip("x");
}
public void track() { internalTracking(true); }
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();
}
}
在类的方法和作用域内,也就是上面代码中的internalTracking方法中if的作用域中定义了一个TrackingSlip类,这个定义在方法或者作用域中的类成为局部内部类。这里你就把它当成一个String,那在if的作用域中创建,那只有在if中才能调用,如果在方法中创建,那也只能在方法的作用域中调用,这个很容易理解。
匿名内部类(这个在内部类中使用是比较多的)
public class Parcel1 {
public Contents contents() {
return new Contents() { // Insert a class definition
private int i = 11;
public int value() { return i; }
}; // Semicolon required in this case
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
public class Parcel2 {
public Wrapping wrapping (int x) {
return new Wrapping (x) { // Insert a class definition
private int i = 11;
public int value() { return i; }
}; // Semicolon required in this case
}
public Contents contents(final int x) {
return new Contents() { // Insert a class definition
private int i = x;
public int value() { return i; }
}; // Semicolon required in this case
}
}
public class Wrapping {
private int i;
public Wrapping(int x) { i = x; }
public int value() { return i; }
}
Parcel1 中的直接new Contents(){}这个就是匿名内部类,见名思意也就是没有名字是直接创建一个类并且只创建一个,方法体里面就是按照正常的我们编写类的方式来就行。这里还有一个细节就是,看Parcel2中的new Wrapping(x)这样我们并没有在方法体中使用,而是直接调用到了Wrapping这个类的构造器,这个时候int x是不需要用final修饰,而在Parcel2中的 contents方法,我们在new Contents()在方法体中 private int i = x使用到了x这个参数,所以在传参数时编译器要求我们使用final修饰。
这里回到我之前写的接口那块使用的工厂类
interface Service {
void method1();
void method2();
}
interface ServiceFactory {
Service getService();
}
class Implementation1 implements Service {
private Implementation1() {}
public void method1() {print("Implementation1 method1");}
public void method2() {print("Implementation1 method2");}
public static ServiceFactory factory =
new ServiceFactory() {
public Service getService() {
return new Implementation1();
}
};
}
class Implementation2 implements Service {
private Implementation2() {}
public void method1() {print("Implementation2 method1");}
public void method2() {print("Implementation2 method2");}
public static ServiceFactory factory =
new ServiceFactory() {
public Service getService() {
return new Implementation2();
}
};
}
class Implementation1Factory implements ServiceFactory {
public Service getService() {
return new Implementation1();
}
}
class Implementation2Factory implements ServiceFactory {
public Service getService() {
return new Implementation2();
}
}
最下面这段代码其实就是返回一个对应的Implementation1对象,而在第一段代码中是可以通过内部类直接省去这两段代码的编写,并且我们只需要返回一个对象,而使用内部类就正好符合我们的要求,使得代码更简洁。
嵌套类
使用static修饰的内部类就是嵌套类。用static修饰,那当编译器编译时肯定是先进行编译static修饰的内部类,而这样的话,那就不需要像上面当调用外部类对象时需要使用一个.this进行调用,当然了外部类的非static修饰的成员,嵌套类也就无法使用了,这个会在检查时编译器会报错。
这里就是比较特殊的,只要不违反语法规则,那么"接口中的任何类都是自动public和static",那么嵌套类当然也要是public修饰(接口中默认)。这就可在接口中的内部类实现该接口!
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface {
public void howdy() {
System.out.println("Howdy!");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
当然了嵌套基层都行,这样
class MNA {
private void f() {}
class A {
private void g() {}
public class B {
void h() {
g();
f();
}
}
}
}
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();
}
}
嵌套在越里面的内部类能够调用的方法越多。
为什么使用内部类
从上面,我们知道了内部类可以继承一个具体实现,外围类不管继承类还是实现了接口,内部类又可以实现另一种实现(主要还是有时候会得到的是抽象类或者类,这是无法进行修改的,当需要多重继承时,可以考虑使用内部类),这样当我们遇到某些场景时也就可以采用到。这也给了“多重继承”进一步完善。
1.闭包(通俗点也就是调用内部类对象)和回调(一个方法中执行时,又一次调用了他自己)。这里看书即可这里不做总结,虽然书里面长篇大论,其实就当做是一种用法就行了。
2.内部类和控制框架。这一块在书中也是长篇大论。其实这里简单一些,就是直接借鉴书中的例子我再举个例子,从上面我们也知道了内部类时是独立的实现,与外围类无不相关。那假设我需要做一个红外线控制器,上面有几个按钮,每个按钮分别有不同的操作,但是它们都要去实现红外线这个接口或者这个基类,但是如果我们直接使用的类来进行实现,只能一个类实现一个按钮操作,而如果我们需要用到几个按钮就需要几个类,最后再把这几个类统一到一起,这样做是可以的,但是代码上会不会很复杂。而如果我们使用几个内部类,这几个内部类都是可以去实现红外线,那么我们就可以把好几个按钮的实现在一个外围类中一次性就能实现,省了很多的步骤,也符合我们的正常人的思维逻辑。这就是控制框架。
局部内部类
class A{}
Class B{}
像上面这样就是局部内部类,而这样做,A,或者B都是可以访问到这个代码块的成员,这样做很大原因就是当A中有一个内部类B的时候,但是还想再多写一个B同名的实现,这个时候就可以使用这个方法。