前言
在读 《Java编程思想 Thinking in Java》 这本书的时候,会有很多示例代码。为了巩固和实践,所以将书上的代码都写上一遍
10.5 在方法和作用域内的内部类
先写个接口Destination:
package com.innerClass;
public interface Destination {
String readLabel();
}
接下来就写,在方法的作用域中创建一个完整的类。这被叫做局部内部类!!!
package com.innerClass;
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");
}
}
下面展示,如何在任意作用域内嵌入一个内部类:
package com.innerClass;
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();
}
//试想一下上面这两句话,写到这里可不可以呢?
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();;
}
}
回答代码中的问题,答案是不可以哦,因为那里是 if的作用域外,超出了TrackingSlip的作用域了!
10.6 匿名内部类
先写个接口,做铺垫啊
package com.innerClass;
public interface Contents {
int value();
}
马上写一个匿名内部类啊
package com.innerClass;
public class Parcel7 {
public Contents contents(){
return new Contents() {
private int i = 11;
@Override
public int value() {
return i;
}
};
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
在contents方法中,return的那个类,没有名字,看吧,是不是很奇怪。
在return一个new的Contents的时候,仿佛听见一个声音,说:“等等,我想在这里插入一个内的定义”。结果就成这个样子了。
这就是匿名内部类啊!!!
对这个奇怪的语法正儿八经的总结一下就是:“创建一个继承自Contents的匿名内部类的对象。通过new表达式返回的引用被自动向上转型为对Contents的引用。”
上述匿名内部类的语法是下述形式的简化形式:
package com.innerClass;
public class Parcel7b {
class MyContents implements Contents{
private int i = 11;
@Override
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,但是如果基类需要一个有参数的构造器,就像下面这样,改怎么办呢?
package com.innerClass;
public class Parcel8 {
public Wrapping wrapping(int x){
return new Wrapping(x){
@Override
public int value() {
return super.value() * 47;
}
};
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
Wrapping这个类我该怎样写,才能正确的被Parcel8使用呢?
很简单!只需要传递合适的参数给基类的构造器即可,就像这样:
package com.innerClass;
public class Wrapping {
private int i;
public Wrapping(int x){
i = x;
}
public int value(){
return i;
}
}
虽然Wrapping只是一个具有具体实现的普通类,但还是被其导出类当作公共“接口”来使用!
如果在匿名类中定义字段时,还要对其执行初始化操作,该咋写呢?就该像下面这样写呀:
package com.innerClass;
public class Parcel9 {
public Destination destination(final String dest){
return new Destination() {
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
注意到了吗?用到了关键字final哦,如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象时,那么编译器就会要求其参数是final的。
实现一个为匿名内部类创建一个构造器的效果:
package com.innerClass;
public abstract class Base {
public Base(int i){
System.out.println("Base constructor, i = "+i);
}
public abstract void f();
}
package com.innerClass;
import com.sun.org.apache.xpath.internal.SourceTree;
public class AnonymousConstructor {
public static Base getBase(int i){
return new Base(i) {
@Override
public void f() {}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
这个例子中呢,变量i,不要求是final的。因为 i 被传递给匿名类的基类的构造器,并没有在匿名类内部直接使用。
带实例初始化的“parcel”形式。
package com.innerClass;
public class Parcel10 {
public Destination destination(final String dest, final float price){
return new Destination() {
private int cost;
{
cost = Math.round(price);
if(cost > 100){
System.out.println("Over budget");
}
}
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel10 p = new Parcel10();
Destination d = p.destination("Tasmania", 101.395F);
}
}
10.6.1 再访工厂方法
使用匿名内部类改造 interfaces/Factories.java 示例:
package com.innerClass;
public interface Service {
void method1();
void method2();
}
package com.innerClass;
public interface ServiceFactory {
Service getService();
}
package com.innerClass;
public class Implementation1 implements Service{
private Implementation1(){}
@Override
public void method1() {
System.out.println("Implementation1 method1");
}
@Override
public void method2() {
System.out.println("Implementation1 method2");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation1();
}
};
}
package com.innerClass;
public class Implementation2 implements Service{
private Implementation2(){}
@Override
public void method1() {
System.out.println("Implementation2 method1");
}
@Override
public void method2() {
System.out.println("Implementation2 method2");
}
public static ServiceFactory factory = new ServiceFactory() {
@Override
public Service getService() {
return new Implementation2();
}
};
}
package com.innerClass;
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);
serviceConsumer(Implementation2.factory);
}
}
改造 interfaces/Games.java 示例:
package com.innerClass.games;
public interface Game {
boolean move();
}
package com.innerClass.games;
public interface GameFactory {
Game getGame();
}
package com.innerClass.games;
public class Checkers implements Game{
private Checkers(){}
private int moves = 0;
private static final int MOVES = 3;
@Override
public boolean move() {
System.out.println("Checkers move " + moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Checkers();
}
};
}
package com.innerClass.games;
public class Chess implements Game{
private Chess(){}
private int moves = 0;
private static final int MOVES = 4;
@Override
public boolean move() {
System.out.println("Chess move "+ moves);
return ++moves != MOVES;
}
public static GameFactory factory = new GameFactory() {
@Override
public Game getGame() {
return new Chess();
}
};
}
package com.innerClass.games;
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);
}
}
10.7 嵌套类
如果不需要内部类对象与外围对象之间有联系,那么可以讲内部类声明成static。这就被称为:嵌套类。
要想理解static应用于内部内时的含义,就必须必须必须的记住一点:普通内部类对象其实隐式的保存了一个引用,这个引用只想它外围的对象。
上菜:
package com.innerClass;
public class Parcel11 {
private static class ParcelContents implements Contents{
private int i = 1;
@Override
public int value() {
return i;
}
protected static class ParcelDestination implements Destination{
private String label;
private ParcelDestination(String whereTo){
label = whereTo;
}
@Override
public String readLabel() {
return label;
}
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 = contents();
Destination d = destination("Tasmania");
}
}
}
在main()中,没有用到Parcel11对象就可以直接使用static修饰的内部类啦,也就是嵌套类。
10.7.1 接口内部的类
这就厉害了,就像下面这样:
package com.innerClass;
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface{
@Override
public void howdy() {
System.out.println("Howdy");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
————————————————————————————
技术无他,唯有熟尔。
知其然,也知其所以然。
踏实一些,不要着急,你想要的岁月都会给你。