5.1 关键字:static
当编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new
关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。有时候希望无论是否产生了对象或无论产生了多少对象的情况下,某些特定的数据在内存空间里只有一份。例如,所有的中国人都有个国家名称,每一个中国人都共享这个国家名称,不必在每一个中国人的实例对象中都单独分配一个用于代表国家名称的变量。
class Circle {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
}
创建两个Circle对象
Circle c1=new Circle(2.0); //c1.radius=2.0
Circle c2=new Circle(3.0); //c2.radius=3.0
Circle类中的变量radius是一个实例变量(instance variable),它属于类的每一个对象,不能被同一个类的不同对象所共享。
上例中c1的radius独立于c2的radius,存储在不同的空间。c1中的radius变化不会影响c2的radius,反之亦然。
如果想让一个类的所有实例共享数据,就用类变量!
类属性、类方法的设计思想
- 类属性作为该类各个对象之间共享的变量。在设计类时,分析哪些类属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
- 如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
使用范围:
- 在Java类中,可用
static
修饰属性、方法、代码块、内部类。
被修饰后的成员具备以下特点:
- 随着类的加载而加载。
- 优先于对象存在。
- 修饰的成员,被所有对象所共享。
- 访问权限允许时,可不创建对象,直接被类调用。
class Circle {
private double radius;
public static String name = "这是一个圆";
public static String getName() {
return name;
}
public Circle(double radius) {
getName();
this.radius = radius;
}
public double findArea() {
return Math.PI * radius * radius;
}
public void display() {
System.out.println("name:" + name + "radius:" + radius);
}
}
public class TestStatic {
public static void main(String[] args) {
Circle c1 = new Circle(2.0);
Circle c2 = new Circle(3.0);
c1.display();
c2.display();
}
}
类变量(class Variable)
类变量(类属性)由该类的所有实例共享。
public class Person {
private int id;
public static int total = 0;
public Person() {
total++;
id = total;
}
}
类变量应用举例
class Person {
private int id;
public static int total = 0;
public Person() {
total++;
id = total;
}
public static void main(String args[]) {
Person Tom = new Person();
Tom.id = 0;
total = 100; // 不用创建对象就可以访问静态成员
}
}
public class OtherClass {
public static void main(String args[]) {
// 不用创建对象就可以访问静态成员
// 访问方式:类名.类属性,类名.类方法
Person.total = 100;
System.out.println(Person.total);
Person c = new Person(); //输出100
System.out.println(c.total); //输出101
}
}
类方法(class Method)
- 没有对象的实例时,可用类名.方法名的形式访问由
static
标记的类方法。 - 在
static
方法内部只能访问类的static
属性,不能访问类的非static
属性。
class Person {
private int id;
private static int total = 0;
public static int getTotalPerson() {
id++; //非法 ,修改为 private static int id;
return total;
}
public Person() {
total++;
id = total;
}
}
public class TestPerson {
public static void main(String[] args) {
System.out.println("Number of total is " + Person.getTotalPerson());
//没有创建对象也可以访问静态方法
Person p1 = new Person();
System.out.println("Number of total is " + Person.getTotalPerson());
}
}
在静态方法里只能直接调用同类中其它的静态成员(包括变量和方法),而不能直接访问类中的非静态成员。这是因为,对于非静态的方法和变量,需要先创建类的实例对象后才可使用,而静态方法在使用前不用创建任何对象。
- 因为不需要实例就可以访问
static
方法,因此**static
方法内部不能有this
,也不能有super
**。 - 重载的方法需要同时为
static
的或者非static
的。
class Person {
private int id;
private static int total = 0;
public static void setTotalPerson(int total) {
//非法,在static方法中不能有this,也不能有super
this.total = total;
}
public Person() {
total++;
id = total;
}
}
public class TestPerson {
public static void main(String[] args) {
Person.setTotalPerson(3);
}
}
静态方法不能以任何方式引用this
和super
关键字。与上面的道理一样,因为静态方法在使用前不用创建任何实例对象,当静态方法被调用时,this
所引用的对象根本就没有产生。
练习
编写一个类实现银行账户的概念,包含的属性有“帐号”、“密码”、“存款余额”、“利率”、“最小余额”,定义封装这些属性的方法。账号要自动生成。 编写主类,使用银行账户类,输入、输出3个储户的上述信息。 考虑:哪些属性可以设计成
static
属性。
class Account {
private String id; //帐号
private String password; //密码
private double balance; //存款余额
private static double rate = 2.75 / 100; //利率
private double minBalance; //最小余额
public Account(String password, double balance, double minBalance) {
this.id = (long) (Math.random() * 1000000000000000L) + "";
this.password = password;
this.balance = balance;
this.minBalance = minBalance;
}
public String toString() {
String info = "id=" + id + ",密码=" + password + ",存款余额=" + balance + ",利率=" + rate + ",最小余额=" + minBalance;
return info;
}
}
public class Test1 {
public static void main(String[] args) {
Account a1 = new Account("111111", 100, 0);
Account a2 = new Account("222222", 200, 0);
Account a3 = new Account("333333", 300, 0);
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
}
}
单例 (Singleton)设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索。
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造方法的访问权限设置为private
,这样,就不能用new
操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
单例(Singleton)设计模式——饿汉式
class Singleton {
//private的构造器,不能在类的外部创建该类的对象
private Singleton() {
}
//私有的,只能在类的内部访问
private static Singleton instance = new Singleton();
//getInstance()为static,不用创建对象即可访问
public static Singleton getInstance() {
return instance;
}
}
public class TestSingle {
public static void main(String args[]) {
Singleton s1 = Singleton.getInstance(); //访问静态方法
Singleton s2 = Singleton.getInstance();
if (s1 == s2) {
System.out.println("s1 is equals to s2!");
}
}
}
单例(Singleton)设计模式——懒汉式
class Singleton {
//1.将构造器私有化,保证在此类的外部,不能调用本类的构造器。
private Singleton() {
}
//2.先声明类的引用
private static Singleton instance = null;
//3.设置公共的方法来访问类的实例
public static Singleton getInstance() {
//3.1如果类的实例未创建,那些先要创建,然后返回给调用者:本类。因此,需要static修饰。
if (instance == null) {
instance = new Singleton();
}
//3.2 若有了类的实例,直接返回给调用者。
return instance;
}
}
public class TestSingle {
public static void main(String args[]) {
Singleton s1 = Singleton.getInstance();//访问静态方法
Singleton s2 = Singleton.getInstance();
if (s1 == s2) {
System.out.println("s1 is equals to s2!");
}
}
}
懒汉式的单例存在线程安全问题。讲到多线程时,再修复。
举例:java.lang.Runtime
5.2 理解main方法的语法
由于Java虚拟机需要调用类的main()
方法,所以该方法的访问权限必须是 public
,又因为Java虚拟机在执行main()
方法时不必创建对象,所以该方法必须是static
的,该方法接收一个String
类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
main()
方法是静态的,因此JVM在执行main()
方法时不创建main()
方法所在的类的实例对象,因而在main()
方法中,我们不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,在以后的例子中会多次碰到。
命令行参数用法举例
public class CommandPara {
public static void main(String[] args) {
for (int i = 0; i < args.length; i++) {
System.out.println("args[" + i + "] = " + args[i]);
}
}
}
//运行程序CommandPara.java
java CommandPara "lisa""bily""Mr Brown"
输出结果:
args[0] = lisa
args[1] = bily
args[2] = Mr Brown
5.3 类的成员之四:初始化块
- 初始化块(代码块)作用:对Java对象进行初始化。
- 程序的执行顺序:
- 一个类中初始化块若有修饰符,则只能被
static
修饰,称为静态代码块(static block )。当类被载入时,类属性的声明和静态代码块先后顺序被执行,且只被执行一次。 static
块通常用于初始化static
(类)属性。
class Person {
public static int total;
static {
total = 100;//为total赋初值
}
…… //其它属性或方法声明
}
- 非静态代码块:没有
static
修饰的代码块。
1.可以有输出语句。 2.可以对类的属性、类的声明进行初始化操作。 3.可以调用静态的变量或方法。 4.若有多个非静态的代码块,那么按照从上到下的顺序依次执行。 5.每次创建对象的时候,都会执行一次。且先于构造器执行。
- 静态代码块:用
static
修饰的代码块。
1.可以有输出语句。 2.可以对类的属性、类的声明进行初始化操作。 3.不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。 4.若有多个静态的代码块,那么按照从上到下的顺序依次执行。 5.静态代码块的执行要先于非静态代码块。 6.静态代码块只执行一次。
静态初始化块举例
class Person {
public static int total;
static {
total = 100;
System.out.println("in static block!");
}
}
public class Test {
public static void main(String[] args) {
System.out.println("total = " + Person.total);
System.out.println("total = " + Person.total);
}
}
输出:
in static block
total=100
total=100
5.4 关键字:final
在Java中声明类、属性和方法时,可使用**关键字final
**来修饰,表示“最终”。
final
标记的类不能被继承。提高安全性,提高程序的可读性。
例:
String
类、System
类、StringBuffer
类
final
标记的方法不能被子类重写。
例:
Object
类中的getClass()
。
final
标记的变量(成员变量或局部变量)即称为常量。名称大写且只能被赋值一次。
final
标记的成员变量必须在声明的同时或在每个构造方法中或代码块中显式赋值,然后才能使用。例:
final double PI=3.14;
final 修饰类
final class A {
}
class B extends A { //错误,不能被继承。
}
final类也被成为太监类!因为,final 类不能被继承无后代。
final 修饰方法
class A {
public final void print() {
System.out.println("A");
}
}
class B extends A {
public void print() { //错误,不能被重写。
System.out.println("B");
}
}
final修饰变量——常量
class A{
private final String INFO = “baidu”; //声明常量
public void print(){
//INFO = “百度”;
}
}
常量名要大写,内容不可修改。——如同古代皇帝的圣旨。
- static final——全局常量。
关键字final应用举例
public final class Test {
public static int totalNumber = 5;
public final int ID;
public Test() {
ID = ++totalNumber; //可在构造方法中给final变量赋值
}
public static void main(String[] args) {
Test t = new Test();
System.out.println(t.ID);
final int I = 10;
final int J;
J = 20;
J = 30; //非法
}
}
排错:
public class Something {
public int addOne(final int x) {
return ++x; // x报错
}
}
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
o.i++;
}
}
class Other {
public int i;
}
// 无措
5.5 抽象类(abstract class)
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
- 用
abstract
关键字来修饰一个类时,这个类叫做抽象类。 - 用
abstract
来修饰一个方法时,该方法叫做抽象方法。
抽象方法:只有方法的声明,没有方法的实现。以分号结束。例:
abstract int abstractMethod(int a);
- 含有抽象方法的类必须被声明为抽象类。
- 抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
- 不能用
abstract
修饰属性、私有方法、构造器、静态方法、final
的方法。
抽象类举例
abstract class A {
abstract void m1();
public void m2() {
System.out.println("A类中定义的m2方法");
}
}
class B extends A {
void m1() {
System.out.println("B类中定义的m1方法");
}
}
public class Test {
public static void main(String args[]) {
A a = new B();
a.m1(); //B类中定义的m1方法
a.m2(); //A类中定义的m2方法
}
}
抽象类应用
抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。
- 解决方案
Java允许类设计者指定:超类声明一个方法但不提供实现,该方法的实现由子类提供。这样的方法称为抽象方法。有一个或更多抽象方法的类称为抽象类。
- Vehicle是一个抽象类,有两个抽象方法。
public abstract class Vehicle {
//计算燃料效率的抽象方法
public abstract double calcFuelEfficiency();
//计算行驶距离的抽象方法
public abstract double calcTripDistance();
}
public class Truck extends Vehicle{
//写出计算卡车的燃料效率的具体方法
public double calcFuelEfficiency(){}
//写出计算卡车行驶距离的具体方法
public double calcTripDistance(){}
}
public class RiverBarge extends Vehicle{
//写出计算驳船的燃料效率的具体方法
public double calcFuelEfficiency(){}
//写出计算驳船行驶距离的具体方法
public double calcTripDistance(){}
}
注意:抽象类不能实例化 new Vihicle() 是非法的。
思考
- 为什么抽象类不可以使用
final
关键字声明?
因为,抽象类必须被子类继承,而
final
修饰的类不能被继承。矛盾了。
- 一个抽象类中可以定义构造器吗?
可以。
练习
编写一个Employee类,声明为抽象类,包含如下三个属性:id,name,salary。提供必要的构造器和抽象方法:work()。对于Manager类来说,他既是员工,还具有奖金(bonus)的属性。请使用继承的思想,设计CommonEmployee类和Manager类,要求类中提供必要的方法进行属性访问。
abstract class Employee {
private int id;
private String name;
private int salary;
abstract void work();
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String toString() {
String info = "我的id=" + id + ",姓名=" + name + ",工资=" + salary;
return info;
}
}
class Manager extends Employee {
private int bonus;
public void setBonus(int bonus) {
this.bonus = bonus;
}
void work() {
System.out.println("我的工作是项目经理");
}
public String toString() {
return super.toString() + ",我的奖金=" + bonus;
}
}
class CommonEmployee extends Employee {
void work() {
System.out.println("我的工作是程序员");
}
}
public class Demo {
public static void main(String[] args) {
CommonEmployee ce = new CommonEmployee();
ce.setId(1001);
ce.setName("张三");
ce.setSalary(5000);
System.out.println(ce);
ce.work();
Manager m = new Manager();
m.setId(100);
m.setName("李四");
m.setSalary(6000);
m.setBonus(1000);
System.out.println(m);
m.work();
}
}
模板方法设计模式(TemplateMethod)
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
- 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
- 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。
abstract class Template {
public final void getTime() {
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("执行时间是:" + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template {
public void code() {
for (int i = 0; i < 10000; i++) {
System.out.println(i);
}
}
}
5.6 更彻底的抽象:接口(interface)
- 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
- 接口(interface)是抽象方法和常量值的定义的集合。
- 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
- 实现接口类:
class SubClass implements InterfaceA{}
- 一个类可以实现多个接口,接口也可以继承其它接口。
接口的特点:
- 用
interface
来定义。 - 接口中的所有成员变量都默认是由
public static final
修饰的。 - 接口中的所有方法都默认是由
public abstract
修饰的。 - 接口没有构造器。
- 接口采用多继承机制。
接口定义举例:
public interface Runner {
int ID = 1;
void start();
public void run();
void stop();
}
//等价于
public interface Runner {
public static final int ID = 1;
public abstract void start();
public abstract void run();
public abstract void stop();
}
- 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则仍为抽象类。
- 接口的主要用途就是被实现类实现——面向接口编程。
- 与继承关系类似,接口与实现类之间存在多态性。
定义Java类的语法格式:先写extends
,后写implements
。
接口应用举例
public interface Runner {
void start();
void run();
void stop();
}
public class Person implements Runner {
public void start() {
// 准备工作:弯腰、蹬腿、咬牙、瞪眼 // 开跑
}
public void run() {
// 摆动手臂
// 维持直线方向
}
public void stop() {
// 减速直至停止、喝水。
}
}
- 一个类可以实现多个无关的接口
interface Runner { void run();}
interface Swimmer { double swim();}
class Creator{public int eat(){…}}
class Man extends Creator implements Runner ,Swimmer{
public void run() {……}
public double swim() {……}
public int eat() {……}
}
- 与继承关系类似,接口与实现类之间存在多态性
public class Test{
public static void main(String args[]){
Test t = new Test();
Man m = new Man();
t.m1(m);
t.m2(m);
t.m3(m);
}
public String m1(Runner f) {f.run();}
public void m2(Swimmer s) {s.swim();}
public void m3(Creator a) {a.eat();}
}
接口的其他问题
- 如果实现接口的类中没有实现接口中的全部方法,必须将此类定义为抽象类。
- 接口也可以继承另一个接口,使用
extends
关键字。
interface MyInterface{
String s="MyInterface";
void absM1();
}
interface SubInterface extends MyInterface{
void absM2();
}
public class SubAdapter implements SubInterface{
public void absM1(){System.out.println("absM1");}
public void absM2(){System.out.println("absM2");}
}
实现类SubAdapter必须给出接口SubInterface以及父接口MyInterface中所有方法的实现。
工厂方法(FactoryMethod)
概述:
定义一个用于创建对象的接口,让子类决定实例化哪一个类。 FactoryMethod使一个类的实例化延迟到其子类。
适用性:
- 当一个类不知道它所必须创建的对象的类的时候。
- 当一个类希望由它的子类来指定它所创建的对象的时候 。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
工厂方法举例
工厂方法(FactoryMethod)
工厂方法模式是设计模式中应用最为广泛的模式,在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。工厂方法解决的就是这个问题,它通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。
代理模式(Proxy)
概述:
为其他对象提供一种代理以控制对这个对象的访问。
interface Object {
void action();
}
class ObjectImpl implements Object {
public void action() {
System.out.println("======");
System.out.println("======");
System.out.println("被代理的类");
System.out.println("======");
System.out.println("======");
}
}
class ProxyObject implements Object {
Object obj;
public void action() {
System.out.println("代理开始");
obj.action();
System.out.println("代理结束");
}
public ProxyObject() {
System.out.println("这是代理类");
obj = new ObjectImpl();
}
}
public class Test2 {
public static void main(String[] args) {
Object ob = new ProxyObject();
ob.action();
}
}
接口用法总结
- 通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。
- 通过接口可以指明多个类需要实现的方法,一般用于定义对象的扩张功能。
- 接口主要用来定义规范。解除耦合关系。
接口和抽象类之间的关系
在开发中,一个类不要去继承一个已经实现好的类,要么继承抽象类,要么实现接口。
练习
定义一个接口用来实现两个对象的比较。
interface CompareObject {
//若返回值是0 ,代表相等
//若为正数,代表当前对象大
//若为负数,代表当前对象小
int compareTo(Object o);
}
定义一个Circle类。 定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
class Circle {
private String name;
private double radius;
public Circle(String name,double radius){
this.name=name;
this.radius=radius;
}
public String getName() {
return name;
}
public double getRadius() {
return radius;
}
}
class ComparableCircle extends Circle implements CompareObject {
public ComparableCircle(String name,double radius){
//调用父类的构造器
super(name,radius);
}
public int compareTo(Object o) {
Circle c = (Circle) o;
if (getRadius() > c.getRadius()) {
System.out.println(getName()+"半径大");
return 1;
} else if (getRadius() < c.getRadius()) {
System.out.println(c.getName()+"半径大");
return -1;
} else {
System.out.println("两个圆一样大");
return 0;
}
}
}
定义一个测试类TestInterface,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小。
public class TestInterface {
public static void main(String[] args) {
ComparableCircle cc1 = new ComparableCircle("圆1",1.2);
ComparableCircle cc2 = new ComparableCircle("圆2",0.1);
cc1.compareTo(cc2);
}
}
接口的应用体会
5.7 类的成员之五:内部类(了解)
- 允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
- 内部类一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
内部类的名字不能与包含它的类名相同。
- 内部类可以使用外部类的私有数据,因为它是外部类的成员,同一个类的成员之间可相互访问。而外部类要访问内部类中的成员需要:内部类.成员或者内部类对象.成员。
分类:
- 成员内部类(static成员内部类和非static成员内部类)
- 局部内部类(不谈修饰符)、匿名内部类
内部类举例
class A {
private int s;
public class B {
public void mb() {
s = 100;
System.out.println("在内部类B中s=" + s); //100
}
}
public void ma() {
B i = new B();
i.mb();
}
}
public class Test {
public static void main(String args[]) {
A o = new A();
o.ma();
}
}
public class A {
private int s = 111;
public class B {
private int s = 222;
public void mb(int s) {
System.out.println(s); //局部变量s 333
System.out.println(this.s); //内部类对象的属性s 222
System.out.println(A.this.s); //外层类对象属性s 111
}
}
public static void main(String args[]) {
A a = new A();
A.B b = a.new B();
b.mb(333);
}
}
内部类特性
内部作为类的成员:
- 可以声明为
final
的。 - 和外部类不同,内部类可声明为
private
或protected
。 - 内部类可以声明为
static
的,但此时就不能再使用外层类的非static
的成员变量。
内部类作为类:
- 可以声明为
abstract
类 ,因此可以被其它的内部类继承。
注意:
非
static
的内部类中的成员不能声明为static
的,只有在外部类或static
的内部类中才可声明static
成员。
匿名内部类
匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。 一个匿名内部类一定是在new
的后面,用其隐含实现一个接口或实现一个类。
语法格式:
举例:
interface A {
void fun1();
}
public class Outer {
public static void main(String[] args) {
new Outer().callInner(new A() {
//接口是不能new但此处比较特殊是子类对象实现接口,只不过没有为对象取名
public void fun1() {
System.out.println("implement for fun1");
}
});// 两步写成一步了
}
public void callInner(A a) {
a.fun1();
}
}
练习
判断输出结果为何?
public class Test {
class Inner {
public int a = 5;
}
public Test() {
Inner s1 = new Inner();
s1.a = 10;
Inner s2 = new Inner();
s2.a = 20;
Test.Inner s3 = new Test.Inner();
System.out.println(s3.a); //5
}
public static void main(String[] args) {
Test t = new Test();
Inner r = t.new Inner();
System.out.println(r.a); //5
}
}