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 ...
随机推荐
- SpringBoot 拦截器 && 拦截之后返回前台自定义格式
1.加入 阿里的 json jar包 <!--json jar相关jar包--> <dependency> <groupId>com.fasterxml.jacks ...
- 在eclipse里面给maven项目打包
eclipse中的“maven install”是用maven打包工程的意思. mvn install 是将用户打包好的jar包安装到本地仓库中,一般没有设置过的话默认在用户目录下的 .m2\下面. ...
- 理解BERT:一个突破性NLP框架的综合指南
概述 Google的BERT改变了自然语言处理(NLP)的格局 了解BERT是什么,它如何工作以及产生的影响等 我们还将在Python中实现BERT,为你提供动手学习的经验 BERT简介 想象一下-- ...
- 热点 | 近期Github热点项目库总结
整理 | Walker 介绍:你有没有想过你会成为一个艺术家,但无奈你不知道如何画画?得益于计算机视觉技术,你可以在ML社区轻松实现这个梦想.更棒的是,Github上ML社区的代码都是开源的! 这就是 ...
- python中的函数及作用域的理解
内置函数 常用的几个内置函数 function des len 求长度 min 求最小值 max 求最大值 sorted 排序 reversed 反向 sum 求和 进制转换函数 function d ...
- 模块 re_正则
模块re_正则 讲正题之前我们先来看一个例子:https://reg.jd.com/reg/person?ReturnUrl=https%3A//www.jd.com/ 这是京东的注册页面,打开页面我 ...
- Mac word文档的消失问题以及解决方案
最近用mac电脑上的Microsoft Word写文档时,出现一个很奇怪的现象:明明我已经保存了文档到某个目录下,但是当我退出Word后,准备去保存目录找文档时发现文档消失了,前一秒还在!!! 通过各 ...
- .Net Core 跨平台开发实战-服务器缓存:本地缓存、分布式缓存、自定义缓存
.Net Core 跨平台开发实战-服务器缓存:本地缓存.分布式缓存.自定义缓存 1.概述 系统性能优化的第一步就是使用缓存!什么是缓存?缓存是一种效果,就是把数据结果存在某个介质中,下次直接重用.根 ...
- 人工智能新手入门学习路线和学习资源合集(含AI综述/python/机器学习/深度学习/tensorflow)
[说在前面]本人博客新手一枚,象牙塔的老白,职业场的小白.以下内容仅为个人见解,欢迎批评指正,不喜勿喷![握手][握手] 1. 分享个人对于人工智能领域的算法综述:如果你想开始学习算法,不妨先了解人工 ...
- Elasticsearch7.6学习笔记1 Getting start with Elasticsearch
Elasticsearch7.6学习笔记1 Getting start with Elasticsearch 前言 权威指南中文只有2.x, 但现在es已经到7.6. 就安装最新的来学下. 安装 这里 ...