Thinking in Java from Chapter 10
From Thinking in Java 4th Edition
内部类
public class Parcel1 {
class Contents {
private int i = 11;
public int value { return i;}
} class Destination {
private String label;
Destination(String whereTo) {
label = whereTo;
} String readLabel() { return label;}
} // Using inner classes looks just like
// using any other class, within Parcel1;
public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLable());
} public static void main(String[] args) {
Parcel1 p = new Parcel1();
p.ship("Tasmania");
}
} /* Output:
Tasmania
*/
更典型的情况是,外部类将有一个方法,该方法返回一个指向内部类的引用
public class Parcel2 {
class Contents {
private int i = 11;
public int value() { return i;}
} class Destination {
private String label;
Destination(String whereTo) {
label = whereTo;
}
String readLabel() { return label;}
} public Destination to(String s) {
return new Destination(s);
} public Contents contents() {
return new Contents();
} public void ship(String dest) {
Contents c = contents();
Destination d = to(dest);
System.out.println(d.readLabel());
} public static void main(String[] args) {
Parcel2 p = new Parcel2();
p.ship("Tasmania");
Parcel2 q = new Parcel2(); // Defining references to inner classes:
Parcel2.Contents c = q.contents();
Parcel2.Destination d = q.to("Borneo");
}
} /* Output:
Tasmania
*/
当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了联系,它能访问其外围对象的所有成员。内部类拥有其外围类的所有元素的访问权:
interface Selector {
boolean end();
Object current();
void next();
} public class Sequence {
private Object[] items;
private int next = 0; public Sequence(int size) { item = new Object[size];} public void add(Object x){
if(next < items.length)
items[next++] = x;
} private class SequenceSelector implements Selector {
private int i = 0;
public boolean end() { return i == items.length; }
public Object current() { return items[i];}
public void next() { if(i < items.length) i++;}
} public Selector selector() {
return new SequenceSelector();
} public static void main(String[] args){
Sequence sequence = new Sequence(10);
for(int i = 0; i < 10; ++i)
sequence.add(Integer.toString(i)); Selector selector = sequence.selector();
while(!selector.end()){
System.out.println(selector.current() + " ");
selector.next();
}
}
} /* Output:
0 1 2 3 4 5 6 7 8 9
*/
要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this:
public class DotThis {
void f() { System.out.println("DotThis.f()");} public class Inner {
public DotThis outer() {
return DotThis.this;
// A plain "this" would be Inner's "this"
}
} public Inner inner() { return new Inner();} public static void main(String[] args){
DotThis dt = new DotThis();
DotThis.Inner dti = dt.inner();
dti.outer().f();
}
} /* Output:
DotThis.f()
*/
要告知某个其他对象,去创建其某个内部类的对象,你必须在new表达式中提供对其他外部类对象的引用,这需要使用.new语法:
public class DotNew {
public class Inner {} public static void main(String[] args){
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
}
要直接创建内部类的对象,你不能按照想象的方式,去引用外部类的名字DotNew,而必须使用外部类的对象来创建该内部类对象.
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地连接到创建它的外部类对象上。
但如果你创建的是嵌套类(静态内部类),那就不需要对外部类对象的引用:
public class Parcel3 {
class Contents {
private int i = 11;
public int value() { return i;}
} class Destination {
private String label;
Destination(String whereTo) { label = whereTo;}
String readLabel() { return label;}
} public static void main(String[] args){
Parcel3 p = new Parcel3(); // Must use instance of outer class
// to create an instance of the inner class:
Parcel3.Contents c = p.new Contents();
Parcel3.Destination d = p.new Destination("Tasmania");
}
}
内部类与向上转型
示例接口:
public interface Destination {
String readLabel();
} public interface Contents {
int value();
}
当取得一个指向基类或接口的引用时,甚至可能无法找出它的确切类型:
class Parcel4 {
private class PContents implements Contents {
private int i = 11;
public int value() { return i;}
} protected class PDestination implements Destination {
private String label;
private PDestination(String whereTo){
label = whereTo;
}
public String readLabel() { return label;}
} public Destination destination(String s){
return new PDestination(s);
} public Contents contents(){
return PContents();
}
} public class TestParcel {
public static void main(String[] args){
Parcel4 p = new Parcel4();
Contents c = p.contents();
Destination d = p.destination("Tasmania"); // Illegal -- can't access private class
//! Parcel4.PContents pc = p.new PContents();
}
}
可以在一个方法里或者在任意的作用域内定义内部类。
在方法的作用域内创建一个完整的内,称作局部内部类:
public class Parcel5{
public Destination destination(String s) {
class PDestination implements Destination {
private String label; private PDestination(String whereTo) {
label = whereTo;
}
public String readLabel() { return label;}
} return new PDestination(s);
} public static void main(String[] args)}{
Parcel5 p = new Parcel5();
Destination d = p.destination("Tasmania");
}
}
1. PDestination类是destination()方法的一部分,所以在destination()方法之外不能访问PDestination。注意出现在return后的向上转型。
2. 在destination()方法内定义内部类,并不意味着在destination()方法执行完毕之后,PDestination就不可用了。
3. 可以在同一个子目录下的任意类中,对某个内部类用标示符PDestination命名,这并不会有名字冲突。
在任意的作用域内嵌入一个内部类:
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("X");
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();
}
}
TrackingSlip类被嵌入if语句,并不是说该类的创建是有条件的:
1. 它其实是与别的类一起被编译过了
2. 在定义TrackingSlip的作用域之外,它是不可用的
匿名内部类
public class Parcel7 {
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();
}
}
这里,Contents是之前定义的接口。这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象”,通过new表达式返回的引用被向上转型为对Contents的引用,上述匿名内部类的语法是下述形式的简化形式:
public class Parcel7b {
class MyContents implements Contents {
private i = 11;
public int value() { return i;}
} public Contents contents() { return new MyContents();} public static void main(String[] args){
Parcel7b p = new Parcel7b();
Contents c = p.contents();
}
}
在匿名内部类中使用了默认的构造器来生成Contents,下面展示,如果你的基类需要一个有参数的构造器应该怎么办:
public class Wrapping {
private int i;
public Wrapping(int x) { i = x;}
public int value() { return i;}
} public class Parcel8 {
public Wrapping wrapping(int x) {
// Base constructor call:
return new Wrapping(x) { // Pass constructor argument
public int value(){
return super.value() * 47;
}
}; // Semicolon required
} public static void main(Sring[] args){
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的:
public class Parcel9 {
// Argument must be final to use inside
// anonymous inner class:
public Destination destination(final String dest) {
return new Destination() {
private String label = dest;
public String readLabel() { return label;}
};
} public static void main(String[] args){
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
如果想做一些类似构造器的行为,在匿名类中不可能有命名构造器(因为它根本没有名字!),但通过实例初始化,就能够达到匿名内部类创建一个构造器的效果。
目标效果:
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i){
{
print("Inside instance initializer");
} public void f(){
print("In anonymous f()");
}
};
} public static void main(String[] args){
Base base = new getBase(47);
base.f();
}
} /* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*/
实例初始化的“parcel” 形式:
public class Parcel10 {
public Destination destination(final String dest, final float price){
return new Destination() {
private int cost; // Instance initialization for each object:
{
cost = Math.round(price);
if(cost > 100)
System.out.println("Over budget!")
} private String label = dest;
public String readLabel() { return label;}
};
} public static void main(String[] args){
Parcel10 p = new Parcel10();
Destination d = p.destination("Tasmania", 101.395F);
}
} /* Output:
Over budget!
*/
运用匿名内部类实现工厂方法:
import static net.mindview.util.Print.*; interface Service {
void method1();
void method2();
} interface ServiceFactory {
Service getService();
} class Implementation1 implements Service {
private Implementation1() {} public method1 { print("Implementation1 method1");}
public method2 { print("Implementation1 method2");} public static ServiceFactory factory =
new ServiceFactory() {
public Service getService(){
return new Implementation1();
}
}
} class Implementation2 implements Service {
private Implementation2() {} public method1 { print("Implementation2 method1");}
public method2 { print("Implementation2 method2");} public static ServiceFactory factory =
new ServiceFactory(){
public getService(){
return new Implementation2();
}
}
} public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
} public static void main(String[] args){
serviceConsumer(Implementation1.factory);
// Implementations are completely interchangeable:
serviceConsumer(Implementation2.factory);
}
} /* Output:
Implementation1 method1
Implementation1 method2
Implementation2 method1
Implementation2 method2
*/
Game类也可以经由同样的改进:
import static net.mindview.util.Print.*; interface Game { boolean move();}
interface GameFactory { Game getGame();} class Checkers implements Game {
private Checkers() {} private int moves = 0;
private static final int MOVES = 3; public boolean move() {
print("Checkers move " + moves);
return ++moves != MOVES;
} public static GameFactory factory = new GameFactory() {
public Game getGame() { return new Checkers(); }
};
} class Chess implements Game {
private Chess() {}
private int moves = 0;
private static final int MOVES = 4; public boolean move() {
print("Chess move " + moves);
return ++moves != MOVES;
} public static GameFactory factory = new GameFactory() {
public Game getGame() { return new Chess();}
};
} public class Games {
public static void playGame(GameFactory factory) {
Game s = factory.getGame();
while(s.move());
} public static void main(String[] args){
playGame(Checkers.factory);
playGame(Chess.factory);
}
} /* Output:
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*/
嵌套类
1. 要创建嵌套类的对象,并不需要其外围类的对象
2. 不能从嵌套类中访问非静态的外围类对象
普通内部类的字段与方法只能放在类的外部层次,所以普通内部类不能有static数据和static字段。但是嵌套类可以包含所有这些东西
public class Parcel11 {
private static class ParcelContents implements Contents {
private int i = 11;
public int value() { return i;}
} protected static class ParcelDestination implements Destination {
private String label;
private ParcelDestination(String whereTo){
label = whereTo;
}
public String readLabel() { return label;} // Nested classes can contain other static elements:
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 c = new contents();
Destination d = destination("Tasmania");
}
}
正常情况下,不能在接口内放置任何代码,但嵌套类可以作为接口的一部分。放到接口中的任何类都是public和static的。因为类是static的,所以这并不违反接口的规则。甚至,可以在内部类中实现其外围的接口:
//: innerclasses/ClassInInterface.java
// {main: ClassInInterface$Test} 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();
}
}
} /* Output:
Howdy!
*/
要运行以上代码,执行java ClassInInterface$Test即可,在Unix/Linux中,符号$必须转义。
可以使用嵌套类来放置测试代码:(运行这个程序,执行java TestBed$Tester即可。)
//: innerClasses/TestBed.java
// Putting test code in a nested class.
// {main: TestBed$Tester} public class TestBed {
public void f() { System.out.println("f()");} public static class Tester {
public static void main(String[] args){
TestBed t = new TestBed();
t.f();
}
}
} /* Output:
f()
*/
这生成了一个独立的类TestBed$Tester。 可以使用这个类来做测试,但不必在发布的产品中包含它,在将产品打包前可以简单地删除TestBed$Tester.class文件。
一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员:
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. 使用内部类
package innerclasses; interface A {}
interface B {}
// 1. Use only one class
class X implements A, B {} // 2. Use inner class
class Y implements A {
B makeB(){
// Anonymous inner class:
return new B() {};
}
} public class MultiInterfaces {
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());
}
}
如果拥有的是抽象的类或具体的类,而不是接口, 那就只能选择内部类实现多重继承:
// With concrete or abstract classes, inner
// classes are the only way to produce the effect
// of "multiple implementation inheritance."
package innerclasses; class D {}
abstract class E {} class Z extends D {
E makeE() { return new E() {}; }
} public class MultiImplementation {
static void takesD(D d) {}
static void takesE(E e) {}
public static void main(String[] args){
Z z = new Z();
takesD(z);
takesE(z.makeE());
}
}
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。可以看出,内部类是面向对象的闭包。
通过内部类提供闭包的功能是优良的解决方案, 它比指针更灵活、更安全:
// Using inner class for callbacks
package innerclasses;
import static net.mindview.util.Print.*; interface Incrementable {
void increment();
} // Very simple to just implement the interface:
class Callee1 implements Incrementable {
private int i = 0; public void increment() {
++i;
print(i);
}
} class MyIncrement {
public void increment() { print("Other operation");}
static void f(MyIncrement mi) { mi.increment();}
} // If your class must implement increment() in
// some other way, you must use an inner class:
class Callee2 extends MyIncrement {
private int i = 0;
public void increment(){
super.increment();
++i;
print(i);
} private class Closure implements Incrementable {
public void increment() {
// Specify outer-class method, otherwise
// you'd get an infinite recursion:
Callee2.this.increment();
}
} Incrementable getCallbackReference() {
return new Closure();
}
} class Caller {
private Incrementable callbackReference;
Caller(Incrementable cbh) { callbackReference = cbh;}
void go() { callbackReference.increment();}
} public class Callbacks{
public static void main(String[] args){
Callee1 c1 = new Callee1();
Callee2 c2 = new Callee2(); MyIncrement.f(c2); Caller caller1 = new Caller(c1);
Caller caller2 = new Caller(c2.getCallbackReference()); caller1.go();
caller1.go(); caller2.go();
caller2.go();
}
} /* Output:
Other operation
1
1
2
Other operation
2
Other operation
3
*/
应用程序框架(application framework)就是被设计用以解决某类特定问题的一个类或一组类。
要运用某个应用程序框架,通常是继承一个类或多个类,并覆盖某些方法。
控制框架(control framework)是一类特殊的应用程序框架,它用来解决响应事件的需求。主要用来响应事件的系统被称为事件驱动系统。
下面的例子包含了某些实现:
// The common methods for any control event.
package innerclasses.controller; public abstract class Event {
private long eventTime;
protected final long delayTime; public Event(long delayTime) {
this.delayTime = delayTime;
start();
} public void start(){ // Allows restarting
eventTime = System.nanoTime() + delayTime;
} public boolean ready() {
return System.nanoTime() >= eventTime;
} public abstract void action();
}
下面的文件包含了一个用来管理并触发事件的实际控制框架:
// The reusable framework for control system.
package innerclasses.controller;
import java.util.*; public class Controller {
// A class from java.util to hold Event objects:
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);
}
} }
}
}
使用内部类,可以在单一的框架里面产生对同一个基类Event的多种导出版本。对于温室系统的每一种行为,都继承一个新的Event内部类,并在要实现的action()中编写控制代码。
温室控制系统:
// This produces a specific application of the
// control system, all in a single class. Inner
// classes allow you to encapsulate different
// functionality for each type of event.
import innerclasses.controller.*; public class GreenhouseControls extends Controller {
private boolean light = false; public class LightOn extends Event {
public LightOn(long delayTime) { super(delayTime);} public void action() {
// Put hardware control code here to
// physically turn on the light.
light = true;
} public String toString() { return "Light is on";}
} public class LightOff extends Event {
public LightOff(long delayTime) { super(delayTime);}
public void action(){
// Put hardware control code here to
// physically turn off the light.
light = false;
}
public String toString() { return "Light is off";}
} private boolean water = false; public class WaterOn extends Event{
public WaterOn(long delayTime) { super(delayTime);} public void action(){
// Put hardware control code here.
water = true;
} public String toString(){
return "Greenhouse water is on";
}
} public class WaterOff extends Event{
public WaterOff(long delayTime) { super(delayTime);} public void action(){
// Put hardware control code here.
water = false;
} public String toString(){
return "Greenhouse water is off";
}
} private String thermostat = "Day";
public class ThermostatNight extends Event{
public ThermostatNight(long delayTime){
super(delayTime);
} public void action(){
// Put hardware control code here.
thermostat = "Night";
} public String toString(){
return "Thermostat on night setting";
}
} public class ThermostatDay extends Event {
public ThermostatDay(long delayTime){
super(delayTime);
} public void action(){
// Put hardware control code here.
thermostat = "Day";
} public String toString() { return "Thermostat on day setting"; }
} // An example of an action that inserts a
// new one of itself into the event list:
public class Bell extends Event {
public Bell(long delayTime) {super(delayTime);} public void action(){
addEvent(new Bell(delayTime));
} public String toString { return "Bing!";}
} public class Restart extends Event{
private Event[] eventList; public Restart(long delayTime, Event[] eventList){
super(delayTime);
this.eventList = eventList;
for(Event e : eventList)
addEvent(e);
} public void action() {
for(Event e : eventList){
e.start(); // Rerun each event
addEvent(e);
}
start(); // Rerun this event
addEvent(this);
} public String toString(){
return "Restarting system";
}
} public static class Terminate extends Event{
public Terminate(long delayTime) { super(delayTime);}
public void action() { System.exit(0);}
public String toString() { return "Terminating";}
}
}
下面的类通过创建一个GreenhouseControls对象,并添加各种不同的Event对象来配置该系统:
// Configure and execute the greenhouse system.
// {Args: 5000}
import innerclasses.controller.*; public class GreenhouseController {
public static void main(String[] args){
GreenhouseControls gc = new GreenhouseControls(); // Instead of hard-wiring, you could parse
// configuration information from a text file here:
gc.addEvent(gc.new Bell(900)); Event[] eventList = {
gc.new ThermostatNight(0),
gc.new LightOn(200),
gc.new LightOff(400),
gc.new WaterOn(600),
gc.new WaterOff(800),m
gc.new ThermostatDay(1400)
}; gc.addEvent(gc.new Restart(2000, eventList)); if(args.length == 1)
gc.addEvent(
new GreenhouseControls.Terminate(
new Integer(args[0])
)
); gc.run();
}
} /* Output:
Bing!
Thermostat on night setting
Light is on
Light is off
Greenhouse water is on
Greenhouse water is off
Thermostat on day setting
Restarting system
Terminating
*/
内部类的继承
因为内部类的构造器必须连接到指向外围类对象的引用,所以在继承内部类的时候,事情会变得复杂。问题在于,那个指向外围类对象的“秘密的”引用必须被初始化,而在导出类中不再存在可连接的默认对象。
class WithInner {
class Inner{}
} public class InheritInner extends WithInner.Inner {
//! InheritInner() {} // Won't compile
InheritInner(WithInner wi) {
wi.super();
} public static void main(String[] args){
WithInner wi = new WithInner();
InheritInner i1 = new InheritInner(wi);
}
}
InheritInner只能继承自内部类,且必须在构造器内使用如下语法:enclosingClassReference.super();,这样才能提供必要的引用,然后程序才能编译通过。
“覆盖”内部类就好像它是外围类的一个方法,其实并不起作用。
import static net.mindview.util.Print.*; 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()
*/
这个例子说明了,当继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。
当然,明确地继承某个内部类也是可以的:
import static net.mindview.util.Print.*; 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()
*/
局部内部类(在方法体里面创建)
1. 局部内部类不能有访问说明符
2. 可以访问当前代码块内的所有常量
3. 可以访问外围类的所有成员
局部内类与匿名内部类创建的比较:
// Holds a sequence of Objects.
import static net.mindview.util.Print.*; interface Counter {
int next();
} public class LocalInnerClass {
private int count = 0; Counter getCounter(final String name) {
// A local inner class:
class LocalCounter implements Counter {
public LocalCounter() {
// Local inner class can have a constructor
print("LocalCounter()");
} public int next() {
printnb(name); // Access local final
return count++;
}
} return new LocalCounter();
} // The same thing with an anonymous inner class:
Counter getCounter2(final String name) {
return new Counter() {
// Anonymous inner class cannot have a named
// constructor, only an instance initializer:
{
print("Counter()");
} public int next(){
printnb(name); // Access local final
return count++;
}
};
} public static void main(String[] args){
LocalInnerClass lic = new LocalInnerClass();
Counter
c1 = lic.getCounter("Local inner "),
c2 = lic.getCounter2("Anonymous inner "); for(int i = 0; i < 5; ++i)
print(c1.next());
for(int i = 0; i < 5; ++i)
print(c2.next());
}
} /* Output:
LocalCounter()
Counter()
Local inner 0
Local inner 1
Local inner 2
Local inner 3
Local inner 4
Anonymous inner 5
Anonymous inner 6
Anonymous inner 7
Anonymous inner 8
Anonymous inner 9
*/
每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息(此信息中产生一个"meta-class",叫做class对象)。
内部类也必须产生一个.class文件以包含它们的信息。它们的命名规则是:外围类的名字加上“$”,再加上内部类的名字。
例如,LocalInnerClass.java生成的.class文件包括:
Counter.class
LocalInnerClass$1.class
LocalInnerClass$1LocalCounte.class
LocalInnerClass$1LocalCounter.class
LocalInnerClass.class
以上中,如果内部类是匿名的,编译器会简单地产生一个数字作为其标示符。
Thinking in Java from Chapter 10的更多相关文章
- Java 集合系列10之 HashMap详细介绍(源码解析)和使用示例
概要 这一章,我们对HashMap进行学习.我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap.内容包括:第1部分 HashMap介绍第2部分 HashMa ...
- Java 集合系列 10 Hashtable详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- 转:java开发的10位牛人
文章来自于:http://it.deepinmind.com/java/2014/04/10/top-10-java-people-you-should-know.html James Gosling ...
- JAVA自学笔记10
JAVA自学笔记10 1.形式参数与返回值 1)类名作为形式参数(基本类型.引用类型) 作形参必须是类的对象 2)抽象类名作形参 需要该抽象类的子类对象,通过多态实现 3)接口名为形参 需要的是该接口 ...
- 2018面向对象程序设计(Java)第10周学习指导及要求
2018面向对象程序设计(Java)第10周学习指导及要求(2018.11.1-2018.11.4) 学习目标 理解泛型概念: 掌握泛型类的定义与使用: 掌握泛型方法的声明与使用: 掌握泛型接口的定 ...
- Java设计模式(10)代理模式(Proxy模式)
理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...
- java基础第10天
Java异常 Exception 异常指的的在运行期出现的错误,在编译阶段出现的语法错误等,不能称之为异常. 编译类异常 必须处理之后才能正常编译(类找不到,IO异常,在API文档中明确写明throw ...
- 你知道吗?Java开发的10位牛人
James Gosling 1983年,Gosling获得了加州大学的计算机科学学士学位.1990年,他获得了卡内基梅隆大学的计算机科学博士学位,师从Bob Sproull.在攻读博士期间,他自己开发 ...
- JAVA基础(10)——IO、NIO
转载:http://blog.csdn.net/weitry/article/details/52964948 JAVA基础系列规划: JAVA基础(1)——基本概念 JAVA基础(2)——数据类型 ...
随机推荐
- Django之Auth模块 实现登录,退出,自带session 与认证功能的一个重要的模块
Auth模板 1. 什么是Auth模块,有什么用? django的auth的模块的使用: auth 是集合注册,登录,注销,session 多个功能集合在一起的模块 2. 使用Auth组件的默认aut ...
- element-ui table 嵌套
嵌套的时时候用template,数据 scope.row.xxx <template> <div> <el-table :data="urls" st ...
- 1.Ansible安装以及配置
本节内容以Centos7为系统环境进行讲解: 1.安装epel源,方便直接yum安装: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun ...
- html 提取 公用部分
在写HTML时,总会遇到一些公用部分,如果每个页面都写那就很麻烦,并且代码量大大增加. 网上查询了几种方法: 1.es6 的 embed 标签. <embed src="header. ...
- java基础-- 之类型转换 和 一些运算符
--- 首先 看一个 Scanner 类 import java.util.Scanner; public class TestScanner { public static void ma ...
- svn 清理失败的解决方法
首先 下载 SQLiteSpy 工具, 解压后如下图所示, 打开 .exe 应用程序,File ,opendatabase 选中wc.db 然后执行 delete from work_qu ...
- [leetcode]87. Scramble String字符串树形颠倒匹配
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrin ...
- Unity3D 移动摇杆处理
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Eve ...
- 针对Web应用的【攻击模式篇】
攻击模式:主动攻击.被动攻击. 主动攻击是指攻击者通过直接访问Web应用,把攻击代码传入的攻击模式. 具有代表性的攻击:SQL注入攻击和OS命令注入攻击. 被动攻击是指利用圈套策略执行攻击代码的攻击模 ...
- MySQL优化(四) 慢查询的定位及优化
一.SQL语句优化的一般步骤: (1)通过 show status 命令了解各种 SQL 的执行效率: (2)定位执行效率较低的 SQL 语句(重点是 Select): (3)通过 explain 分 ...