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 ...
随机推荐
- 二维数组及Arrays工具类
1.二维数组 概念: 数组中的每一个元素类型都是一维数组 二维数组初始化方式: 静态初始化: 格式: 元素类型[][] 数组名 = new 元素类型[][]{{一维数组1},{一维数组2},{一维数组 ...
- 洛谷1363 幻象迷宫dfs
题目网址:https://www.luogu.com.cn/problem/P1363 迷宫是无限多块地图拼接而成的,问是否可以在迷宫中走无限远.解决方案是dfs,走出初始地图之后的位置映射到原位置( ...
- 题解 P2755 【洗牌问题】
这是本人的第一篇题解 请多多宽恕 这一道题其实不要用数组 我们来观察一下n=3时的情况: 原: 1 2 3 4 5 6 4 1 5 2 6 3 2 4 6 1 3 5 1 2 3 4 5 6 我们去观 ...
- SQL 分组内求最大N个或最小N个
题目描述 表 Employee +----+-------+--------+--------------+ | Id | Name | Salary | DepartmentId | +----+- ...
- sql-lib闯关61-65
第六十一关 和六十关基本一样,就是变成了单引号和双括号,这好像是第一次遇见双括号 爆数据库名 ?id=1'))and extractvalue(1, concat(0x5c, (select da ...
- vscode vue 格式化 ESLint 检查 单引号 双引号 函数括号报错问题
vscode vue 格式化 最近重新搞了下电脑,重装了 vscode 软件,在用 vue 写项目的时候,照例开启了 ESLint 语法检查,但是发现在使用 vscode 格式化快捷键的时候(shif ...
- 不可思议的hexo,五分钟教你免费搭一个高逼格技术博客
引言 作为程序员拥有一个属于自己的个人技术博客,绝对是百利无一害的事,不仅方便出门装b,面试时亮出博客地址也会让面试官对你的好感度倍增.经常能在很多大佬的技术文章的文末,看到这样一句话: " ...
- return console.log()结果为undefined现象的解答
console.log总是出现undefined--麻烦的console //本文为作者自己思考后总结出的一些理论知识,若有错误,欢迎指出 bug出现 需求如下:新建一个car对象,调用其中的de ...
- [洛谷2671]求和<前缀和&模拟>
题目链接:https://www.luogu.org/problemnew/show/P2671 这是noip2015普及组的第三题,谁说的普及组的题就一定水的不行,这道题就比较有意思的 这道题的暴力 ...
- STL之map与pair与unordered_map常用函数详解
STL之map与pair与unordered_map常用函数详解 一.map的概述 map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称 ...