Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes
The inner class is a valuable feature because it allows you to group classes that logically belong together and to control the visibility of one within the other. However, it's important to understand that inner classes are distinctly different from composition.
The kind of code you can write with inner classes is more elegant and clear.
More typically, an outer class will have a method that returns a reference to an inner class.
If you want to make an object of the inner class anywhere except from within a non-static method of the outer class, you must specify the type of that object as OuterClassName.InnerClassName.
The linke to the outer class
When you create an inner class, an object of the inner class has a link to the enclosing object that made it, and so it can access the members of the enclosing object. In addition, inner class have access rights to all the elements in the enclosing class.
The inner class secretly captures a reference to the particular object of the enclosing class that was responsible for creating it. An object of an inner class can be created only in association with an objecct of the enclosing class (When ,as you shall see, the inner class is non-static).
Using .this and .new
If you need to produce the reference to the outer-class object, you name the outer class followed by a dot and this.
Sometimes you want to tell some other object to create an object of one of its inner classes. To do this you must provide a reference to the outer-class object in the new expression, using the .new syntax.
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
It's not possible to create an object of the inner class unless you already have an object of the outer class. This is because the object of the inner class is quietly connected to the object of the outer class that it was made from. However, if make a nested class (a static inner class), then it doesn't need a reference to the outer-class object.
Inner classes and upcasting
Inner class really come into their own (有了用武之地) when you start upcasting to a base cass, and in particular to an interface.
Inner classes in methods and scopes
In general, the code that you'll write and read involving inner classes will be "plain" inner classes that are simple and easy to understand. However, the syntax for inner classes covers a number of other, more obscure techniques. Inner classes can be created within a method or even an arbitrary scope. Theare are two reasons for doing this:
1. As shown previously, you're implementing an interface of some kind so that you can create and return a reference.
2. You're solving a complicated problem and you want to create a class to aid in youre solution, but you don't want to publicly available.
The class created within the scope of a method is called a local inner class.
The fact that the class is placed inside a method doesn't mean that The object of the class is not a valid object once the method returns.
The class is nested inside the scope of an if statement. This does not mean that the class is conditionally created--it gets compiled along with everything else. However, it's not available outside the scope in which it is defined. Other than that, it looks just like an ordinary class.
Anonymous inner classes
public Contents contents() {
return new Contents() { // Insert a class definition
private int i = 11;
public int value() { return i;}
}; // Semicolon required in this case
}
What this strange syntax means is "Create an object of an anonymous class that's inherited from Contents." The reference returned by the new expression is automatically upcast to a Contents reference.
The anonymous inner-class syntax is a shorthand for:
class Mycontents implements Contents {
private int i = 11;
public int value() { return i;}
}
public Contents contents() {return new MyContents();}
return new Wrapping(x) { // Pass constructor argument.
public int value() {
return super.value() * 47;
}
}; // Semicolon required
public Destination destination (final String dest) {
return new Destination() {
private String label = dest; // initialization
public String readLabel() {return label; }
};
}
虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用。
You can't have a named constructor in an anonymous class (since there's no name!), but with instance initialization, you can, in effect, create a constructor for an anonymous inner class.
return new Base(j) {
{ print("Inside instance initializer"); }
public void f() {...};
}
It's limited; you can't overload instance initializers, so you can have only one of these constructors.
Anonymous inner class are somewhat limited compared to regular inheritance, because they can either extend a class or implement an interface, but not both. And if you do implement an interface, you can only implement one.
Factory Method revisited
You often only need a single factory object, and so here it has been created as a static field in the Service implementation by annoymous inner class.
Nested classes
A nested class means:
1. You don't need an outer-class object in order to create an object of a nested class.
2. You can't access a non-static outer-class object from an object of a nested class.
Fields and methods in ordinary inner classes can only be at the outer level of a class, so ordinary inner classes cant have static data, static fields, or nested classes. Howover, nested classes can have all of these.
A nested class does not have a special this reference, which makes it analogous to a static method.
Classes inside interfaces
Any class you put inside an interfae is automatically public and static.
You can even implement the surrounding interface in the inner class.
It's convenient to nest a class inside an interface when you want to create some common code to be used with all different implementations of that interface.
Java TestBed$Tester
Reaching outward from a multiply nested class
Why inner classes ?
an inner class provides a kind of window into the outer class.
A question that cuts to the heart of inner classes is this: If I just need a reference to an interface, why don't I just make the outer class implement that interface? The answer is that you can't always have the convenience of interfaces-sometimes you're working with implementations.
Each inner class can independently inherit from an implementation. Thus, the inner class is not limited by whether the outer class is already inheriting from an implementation
One way to look at the inner class is as the rest of the solution of the multiple-inheritance problem.
If you didn't need to solve the "multiple implementation inheritance" problem, you could conceivably code around everything else without the need for inner classes. But with inner classes you have these additional features:
1. The inner class can have multiple instances, each with its own state information that is independent of the information in the outer class object.
2. In a single outer class you can have several inner classes, each of which implements the same interface or inherits from the same class in a different way.
3. The point of creation of the inner-class object is not tied to the creation of the outer-class obect (??)
4. There is no potentially confusing "is-a" relationship with the inner class; it's a separate entity.
Closures & callbacks (闭包和回调)
A closure is a callable object that retains information from the scope in which it was created. From this definition, you can see that an inner class is an object-oriented closure, because it doesn't just contain each piece of iinformation from the outer-class object ("the scope in which it was created"), but it automatically holds a reference back to the whole outer-class object, where it has permission to manipulate all the members, even private ones.
With a callback, some other object is given a piece of information that allows it to call back into the originating object at some later point. But a callback is implemented using a pointer.
The closure provided by the inner class is a good solution-more flexible and far safer than a pointer.
Inner classes & control frameworks
An application framework is a class or a set of classes that's designed to solve a particular type of problem.(应用框架的定义:用于解决某种类型问题的一个类或一组类)
application framework is an example of the Template Method design pattern (模板方法设计模式)
The Template Method contains the basic structure of the algorithm, and it calls one or more overrideable methods to complete the action of that algorithm.
设计模式就是将变化的事物和保存不变的事物分离开。
Template Method 就是保持不变的部分,而可覆盖的方法就是变化的部分
A control framework is a particular type of application framework dominated by the need to response to events. (控制框架是一类特殊的应用程序框架,用来解决响应事件的需求)
A system the primarily responds to events is called an event-driven system. (事件驱动系统)
Java Swing library is a control framework
public class Controller {
private List<Event> eventList = new ArrayList<Event>();
public void addEvent(Event c) { eventList.add(c); }
public void run() {
while(eventList.size() > 0)
// Make a copy so you're not modifying the list
// while you're selecting the elements in it:
for (Event e : new ArrayList<Event>(eventList))
if (e.ready()) {
System.out.println(e);
e.action(); // 变动部分
eventList.remove(e);
}
}
}
The is where inner class comme into play. They allow two things:
1. The entire implementation of a control framework is created in a single class, thereby encapsulating everything that's unique about that implementation. Inner classes are used to express the many different kinds of action() necessary to solve the problem.
2. Inner classes keep this implementation from becoming awkward, since you're able to easily access any of the members in the outer class. Without the ability the code might become unpleasant enough that you'd end up seeking an alternative.
Inheriting from inner classes
Because the inner-class constructor must attach to a reference of the enclosing class object, things are slightly complicated when you inherit from an inner class. The problem is that the "secret" reference to the enclosing class object must be initialized, and yet in the derived class there’s no longer a default object to attach to. You must use a special syntax to make the association explicit
class WithInner {
class Inner {}
}
public class InheritInner extends WithInner.Inner {
// ! InheritInner() {} // Won't compile
InheritInner(WithInner wi) { //******
wi.super();
}
}
Can inner classes be overridden ?
class Egg {
private Yolk y;
protected class Yolk {
public Yolk { print("Egg.Yolk)"); }
}
public Egg() {
print("New Egg()");
y = new Yolk();
}
}
public class BigEgg extends Egg {
public class Yolk {
public Yolk { print("BigEgg.Yolk()"); }
}
public static void main(String[] args) {
new BigEgg();
}
} /* Output:
New Egg()
Egg.Yolk()
*/
The two inner classes are completely separate entities, each in its own namespace. However, it’s still possible to explicitly inherit from the inner class
class Egg2 {
protected class Yolk {
public Yolk() { print("Egg2.Yolk()"); }
public void f() { print("Egg2.Yolk.f()");}
}
private Yolk y = new Yolk();
public Egg2() { print("New Egg2()"); }
public void insertYolk(Yolk yy) { y = yy; }
public void g() { y.f(); }
}
public class BigEgg2 extends Egg2 {
public class Yolk extends Egg2.Yolk {
public Yolk() { print("BigEgg2.Yolk()"); }
public void f() { print("BigEgg2.Yolk.f()"); }
}
public BigEgg2() { insertYolk(new Yolk()); }
public static void main(String[] args) {
Egg2 e2 = new BigEgg2();
e2.g();
}
} /* Output:
Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()
*/
Local inner classes
A local inner class canot have an acces specifier because it isn't part of the outer class, but it does have access to the final variables in the current code block and all the members of the enclosing class.
Since the name of the local inner class is not accessible outside the method, the only justification for using a local inner class instead of an anonymous inner class is if you need a named constructor and/ or an overloaded constructor, since an anonymous inner class can only use instance initialization.
Another reason to make a local inner class rather than an anonymous inner class is if you need to make more than one object of that class.
Inner-class identifiers
If inner classes are anonymous, the compiler simply starts generating numbers as inner-class identifiers. If inner classes are nested within inner classes, their names are simply appended after a ‘$’ and the outer-class identifier (s).
Summary
Interfaces and inner classes solve the same problem that C++ attempts to solve with its multiple inheritance (MI) feature.
Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十)之Inner Classes的更多相关文章
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information
Runtime type information (RTTI) allow you to discover and use type information while a program is ru ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions
The ideal time to catch an error is at compile time, before you even try to run the program. However ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(八)之Reusing Classes
The trick is to use the classes without soiling the existing code. 1. composition--simply create obj ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(七)之Access Control
Access control ( or implementation hiding) is about "not getting it right the first time." ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(六)之Initialization & Cleanup
Two of these safety issues are initialization and cleanup. initialization -> bug cleanup -> ru ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十三)之Strings
Immutable Strings Objects of the String class are immutable. If you examine the JDK documentation fo ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(二)之Introduction to Objects
The genesis of the computer revolution was a machine. The genesis of out programming languages thus ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十一)之Holding Your Objects
To solve the general programming problem, you need to create any number of objects, anytime, anywher ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(九)之Interfaces
Interfaces and abstract classes provide more structured way to separate interface from implementatio ...
随机推荐
- mybatis入门详解
一.mybatis-config.xml文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYP ...
- hackerone或PayPal转账到国内银行卡
1.首先hackerone会提示有W9那么一说,这个是美国人纳税的,我们是中国人不需要纳税的,只要给美国税务局发邮件说你是中国人不需要纳税就OK了.具体操作百度. 2.如此就会成功转账到你的PayPa ...
- python之路---协程
阅读目录 一 引子 二 协程介绍 三 Greenlet模块 四 Gevent模块 引子 之前我们学习了线程.进程的概念,了解了在操作系统中进程是资源分配的最小单位,线程是CPU调度的最小单位.按道理来 ...
- 原来 CPU 为程序性能优化做了这么多
本文主要来学习内存屏障和 CPU 缓存知识,以便于我们去了解 CPU 对程序性能优化做了哪些努力. 首先来看下 CPU 缓存: CPU 缓存 CPU 缓存是为了提高程序运行的性能,CPU 在很多处理上 ...
- 【2019牛客暑期多校第一场】E题ABBA
题目链接 大致题意 有(n+m)(n + m)(n+m)个字母A和(n+m)(n + m)(n+m)个字母B,组成一个长度为 2∗(n+m)2*(n + m)2∗(n+m)的字符串,并且使得字符串中有 ...
- python中的抽象类
今天给大家介绍一下python中一个强大的功能:抽象类 因为最近发现很多同事不理解抽象类,正好抽空写篇博客,给大家介绍一下抽象类 抽象类的作用就是控制子类的方法的名称,要求子类必须按照父类的要求的实现 ...
- Java导出Excel文件
/** * 导出 用get请求 * @param response * @param * @throws IOException */ @RequestMapping(value = "/d ...
- HDU 3303 Harmony Forever 前缀和+树状数组||线段树
Problem Description We believe that every inhabitant of this universe eventually will find a way to ...
- 深入理解JavaScript中的堆与栈 、浅拷贝与深拷贝
JavaScript中的浅拷贝与深拷贝 学了这么长时间的JavaScript想必大家对浅拷贝和深拷贝还不太熟悉吧,今天在项目中既然用到了,早晚也要理清一下思路了,在了解之前,我们还是先从JavaSc ...
- Python python 数据类型的相互转换
# number 之间的相互转换 # int <=> float var1 = 1; print(type(var1)) #<class 'int'> res1 = float ...