7.1 类的封装
封装是面向对象编程的核心思想,将对象的属性和行为封装起来,其载体就是类
代码
public class H7_1 {
public static void main(String[] args) {
String cookName="Tom Cruise";//厨师的名字叫Tom Cruise
System.out.println("**请让厨师为我做一份香辣肉丝。***");
System.out.println(cookName + "切葱花");
System.out.println(cookName + "洗蔬菜");
System.out.println(cookName + "开始烹饪" + "香辣肉丝");
System.out.println("**请问厨师叫什么名字?***");
System.out.println(cookName);
System.out.println("**请让厨师给我切一点葱花。***");
System.out.println(cookName + "切葱花");
}
}
结果
代码
public class H7_2 {
public static void main(String[] args) {
Cook1 cook = new Cook1();// 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***");
cook.cooking("香辣肉丝");// 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");
System.out.println(cook.name);// 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");
cook.cutOnion();// 厨师去切葱花
}
}
class Cook1 {
String name;// 厨师的名字
public Cook1() {
this.name = "Tom Cruise";// 厨师的名字叫Tom Cruise
}
void cutOnion() {// 厨师切葱花
System.out.println(name + "切葱花");
}
void washVegetavles() {// 厨师洗蔬菜
System.out.println(name + "洗蔬菜");
}
void cooking(String dish) {// 厨师烹饪顾客点的菜
washVegetavles();
cutOnion();
System.out.println(name + "开始烹饪" + dish);
}}
结果
代码
public class H7_3 {
public static void main(String[] args) {
Cook2 cook = new Cook2();// 创建厨师类的对象
System.out.println("**请让厨师为我做一份香辣肉丝。***");
cook.cooking("香辣肉丝");// 厨师烹饪香辣肉丝
System.out.println("**你们的厨师叫什么名字?***");
System.out.println(cook.name);// 厨师回答自己的名字
System.out.println("**请让厨师给我切一点葱花。***");
cook.cutOnion();// 厨师去切葱花
}
}
class Cook2 {
private String name;//厨师的名字
public Cook2() {
this.name = "Tom Cruise";//厨师的名字叫Tom Cruise
}
private void cutOnion() {//厨师切葱花
System.out.println(name + "切葱花");
}
private void washVegetavles() {//厨师洗蔬菜
System.out.println(name + "洗蔬菜");
}
void cooking(String dish) {//厨师烹饪顾客点的菜
washVegetavles();
cutOnion();
System.out.println(name + "开始烹饪" + dish);
}
}
代码
public class H7_4 {
private Cook2 cook = new Cook2();// 餐厅封装的厨师类
public void takeOrder(String dish) {// 下单
cook.cooking(dish);// 通知厨师做菜
System.out.println("您的菜好了,请慢用。");
}
public String saySorry() {// 拒绝顾客请求
return "抱歉,餐厅不提供此项服务。";
}
public static void main(String[] args) {
H7_4 water = new H7_4();// 创建餐厅对象,为顾客提供服务
System.out.println("**请让厨师为我做一份香辣肉丝。***");
water.takeOrder("香辣肉丝");// 服务员给顾客下单
System.out.println("**你们的厨师叫什么名字?***");
System.out.println(water.saySorry());// 服务员给顾客善意的答复
System.out.println("**请让厨师给我切一点葱花。***");
System.out.println(water.saySorry());// /服务员给善意的答复顾客
}
}
结果
7.2 类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性,在程序中复用已经定义完善的类不仅可以减少软件开发周期,还可以提高软件的可维护性和可扩展性。
7.2.1 extends 关键字
在Java 中,让一个类继承另一个类,用 extends 关键字,语法如下:
child extends parents
代码
class Computer {// 父类:电脑
String screen = "液晶显示屏";
void startup() {
System.out.println("电脑正在开机,请等待...");
}
}
public class H7_5 extends Computer {
String battery = "5000毫安电池";// 子类独有的属性
public static void main(String[] args) {
Computer pc = new Computer();// 电脑类
System.out.println("computer的屏幕是:" + pc.screen);
pc.startup();
H7_5 ipad = new H7_5();// 平板电脑类
System.out.println("pad的屏幕是:" + ipad.screen);// 子类可以直接使用父类属性
System.out.println("pad的电池是:" + ipad.battery);// 子类独有的属性
ipad.startup();// 子类可以直接使用父类方法
}
}
结果
7.2.2 方法的重写
在继承中还有一种特殊的重写方式,子类与父类的成员方法,返回值方法,参数类型及个数完全相同,唯一不同的是方法实践内容,这种特殊重写方式被称为重构
代码
class Computer2 {// 父类:电脑
void showPicture() {
System.out.println("鼠标点击");
}
}
public class H7_6 extends Computer2{
void showPicture() {
System.out.println("手指点击触摸屏");
}
public static void main(String[] args) {
Computer2 pc = new Computer2();// 电脑类
System.out.print("pc打开图片:");
pc.showPicture();// 调用方法
H7_6 ipad = new H7_6();// 平板电脑类
System.out.print("ipad打开图片:");
ipad.showPicture();// 重写父类方法
Computer2 computerpad = new H7_6();// 父类声明,子类实现
System.out.print("computerpad打开图片:");
computerpad.showPicture();// 调用父类方法,实现子类重写的逻辑
}
}
结果
代码
class Computer3 {// 父类:电脑
String sayHello(){
return "欢迎使用";
}
}
public class H7_7 extends Computer3{
String sayHello() {// 子类重写父类方法
return super.sayHello() + "平板电脑";// 调用父类方法,在其结果后添加字符串
}
public static void main(String[] args) {
Computer3 pc = new Computer3();// 电脑类
System.out.println(pc.sayHello());
H7_7 ipad = new H7_7();// 平板电脑类
System.out.println(ipad.sayHello());
}
}
结果
7.2.3 所有类的父类——Object类
在开始学习使用class 关键字定义类时,就应用了继承原理,因为在Java中,所有的类型都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,是Java类层中的最高层类。当创建一个类时,总是在继承,除非某个类已经指定要从其他类继承,否则它就是从java.lang.Object 类继承而来的,可见 Java 中的每个类都源于java.lang.Object 类,如 String、Integer 等类都是继承于 Object 类;除此之外自定义的类也都继承于Object 类。由于所有类都是 Object 子类,所以在定义类时,省略了 extends Object关键字
代码
public class H7_8 {
public String toString() { //重写toString()方法
return "在" + getClass().getName() + "类中重写toString()方法";
}
public static void main(String[] args) {
System.out.println(new H7_8()); //打印本类对象
}
}
结果
代码
class V { // 自定义类V
}
public class H7_9 {
public static void main(String[] args) {
String s1 = "123"; // 实例化两个对象,内容相同
String s2 = "123";
System.out.println(s1.equals(s2)); // 使用equals()方法调用
V v1 = new V(); // 实例化两个V类对象
V v2 = new V();
System.out.println(v1.equals(v2)); // 使用equals()方法比较v1与v2对象
}
}
结果
7.3 类的多态
多态意为一个名字可具有多种语义,在程序设计语言中,多态性是指“一种定义,多种实现”例如,运算符“+”作用于两个整型量时是求和,而作用于两个字符型量时则是将其连接在一起。利用多态可以使程序具有良好的扩展性,并可以对所有类对象进行通用的处理。类的多态性可以从两方面体现:一是方法的重载,二是类的上下转型。
7.3.1 方法的重载
方法的存在就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
代码
public class H7_10 {
// 定义一个方法
public static int add(int a) {
return a;
}
// 定义与第一个方法参数个数不同的方法
public static int add(int a, int b) {
return a + b;
}
// 定义与第一个方法相同名称、参数类型不同的方法
public static double add(double a, double b) {
return a + b;
}
// 定义一个成员方法
public static int add(int a, double b) {
return (int) (a + b);
}
// 这个方法与前一个方法参数次序不同
public static int add(double a, int b) {
return (int) (a + b);
}
// 定义不定长参数
public static int add(int... a) {
int s = 0;
// 根据参数个数循环操作
for (int i = 0; i < a.length; i++) {
s += a[i];// 将每个参数的值相加
}
return s;// 将计算结果返回
}
public static void main(String args[]) {
System.out.println("调用add(int)方法:" + add(1));
System.out.println("调用add(int,int)方法:" + add(1, 2));
System.out.println("调用add(double,double)方法:" + add(2.1, 3.3));
System.out.println("调用add(int a, double b)方法:" + add(1, 3.3));
System.out.println("调用add(double a, int b) 方法:" + add(2.1, 3));
System.out.println("调用add(int... a)不定长参数方法:"+ add(1, 2, 3, 4, 5, 6, 7, 8, 9));
System.out.println("调用add(int... a)不定长参数方法:" + add(2, 3, 4));
}
}
结果
7.3.2 向上转型
对象类型的转换在Java编程中经常遇到,主要包括向上转型与向下转型操作。
代码
class Quadrangle { // 四边形类
public static void draw(Quadrangle q) { // 四边形类中的方法
// SomeSentence
}
}
public class H7_11 extends Quadrangle{
public static void main(String args[]) {
H7_11 p = new H7_11(); // 实例化平行四边形类对象引用
draw(p); // 调用父类方法
}}
结果
7.3.3 向下转型
通过向上转型可以推理出,向下转型是较抽象类转换为较具体的类。
代码
class Quadrangle {
public static void draw(Quadrangle q) {
// SomeSentence
}
}
public class H7_12 extends Quadrangle {
public static void main(String args[]) {
draw(new H7_12());
// 将平行四边形类对象看作是四边形对象,称为向上转型操作
Quadrangle q = new H7_12();
H7_12 p = (H7_12) q; // 将父类对象赋予子类对象
// //将父类对象赋予子类对象,并强制转换为子类型
//Parallelogram p = (Parallelogram) q;
}
}
结果
在Parallelogram 子类的主方法中将父类 Quadrangle 的对象赋值给子类Parallelogram 的对象的引用变量将使程序产生错误。
7.3.4 instanceof关键字
当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生Class CastException 异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例。这个判断通常使用instanceof操作符来完成。可以使用 instanceof操作符判断是否一个类实现了某个接口(接口会在7.4 节中进行介绍),也可以用它来判断一个实例对象是否属于一个类。
instanceof的语法格式如下:
myobject instanceof ExampleClass
myobject :某类的对象引用
ExampleClass:某个类
代码
class Quadrangle {
public static void draw(Quadrangle q) {
// SomeSentence
}
}
class Square extends Quadrangle {
// SomeSentence
}
class Anything {
// SomeSentence
}
public class H7_13 extends Quadrangle {
public static void main(String args[]) {
Quadrangle q = new Quadrangle(); // 实例化父类对象
// 判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof H7_13) {
H7_13 p = (H7_13) q; // 进行向下转型操作
}
// 判断父类对象是否为Parallelogram子类的一个实例
if (q instanceof Square) {
Square s = (Square) q; // 进行向下转型操作
}
// 由于q对象不为Anything类的对象,所以这条语句是错误的
// System.out.println(q instanceof Anything);
}
}
7.4 抽象类与接口
7.4.1 抽象类与抽象方法
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。回想继承和多态原理,继承树中越是在上方的类越抽象,如鸽子类继承鸟类、鸟类继承动物类等。在多态机制中,并不需要将父类初始化对象,我们需要的只是子类对象,所以在Java语言中设置抽象类不可以实例化对象,因为图形类不能抽象出任何一种具体图形,但它的子类却可以。
Java 中定义抽象类时,需要使用 abstract 关键字,其语法如下: [权限修饰符] abstract class 类名{
类体 }
用abstract 关键字定义的类称为抽象类,而使用abstract 关键字定义的方法称为抽象方法,抽象方法的定义语法如下:
[权限修饰符]abstract 方法返回值类型方法名(参数列表);
使用抽象类和抽象方法时需要遵循以下原则:
(1)在抽象类中可以包含抽象方法,也可以不包含抽象方法,但是包含了抽象方法的被定位为抽象类
(2)抽象类不能直接实例化,即使抽象类中没有声明抽象方法也不能实例化。
(3)抽象类被继承后,子类需要实现其中所有的抽象方法。
(4)如果继承抽象类的子类也被声明为抽象类,则可以不用实现父类中所有的抽象方法。
代码
public interface IMather {
void watchTV();// 看电视的方法
void cooking();// 做饭的方法
}
public class TaobaoMarker extends Market {
@Override
public void shop() {
// TODO Auto-generated method stub
System.out.println(name+"网购"+goods);
}
}
public class WallMarket extends Market {
@Override
public void shop() {
// TODO Auto-generated method stub
System.out.println(name+"实体店购买"+goods);
}
}
public class H7_14 {
public static void main(String[] args) {
Market market = new WallMarket();// 使用派生类对象创建抽象类对象
market.name = "沃尔玛";
market.goods = "七匹狼西服";
market.shop();
market = new TaobaoMarker();// 使用派生类对象创建抽象类对象
market.name = "淘宝";
market.goods = "韩都衣舍花裙";
market.shop();
}
}
7.4.2接口的声明及实现
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。对于1小节中遗留的问题,可以将draw()方法封装到一个接口中,这样可以让一个类既能继承图形类,又能实现draw()方法接口,这就是接口存在的必要性
代码
interface drawTest { // 定义接口
public void draw(); // 定义方法
}
// 定义平行四边形类,该类实现了drawTest接口
class ParallelogramgleUseInterface implements drawTest {
public void draw() { // 由于该类实现了接口,所以需要覆盖draw()方法
System.out.println("平行四边形.draw()");
}
}
// 定义正方形类,该类实现了drawTest接口
class SquareUseInterface implements drawTest {
public void draw() {
System.out.println("正方形.draw()");
}
}
public class H7_15 {
public static void main(String[] args) {
drawTest[] d = { // 接口也可以进行向上转型操作
new SquareUseInterface(), new ParallelogramgleUseInterface() };
for (int i = 0; i < d.length; i++) {
d[i].draw(); // 调用draw()方法
}
}}
结果
7.4.3 多重继承
在Java中类不允许多重继承,但使用接口就可以实现多重继承,因为一个类可以同时实现多个接口,这样可以将所有需要实现的接口放置在implements关键字后并使用逗号“”隔开,但这可能会在一个类中产生庞大的代码量,因为继承一个接口时需要实现接口中所有的方法。
通过接口实现多重继承的语法如下:
class 类名 implements 接口1,接口2,…,接口n
代码
public interface IFather {
void smoking();// 抽烟的方法
void goFishing();// 钓鱼的方法
}
public interface IMather {
void watchTV();// 看电视的方法
void cooking();// 做饭的方法
}
public class H7_16 implements IFather, IMather {// 继承IFather接口和IMather接口
@Override
public void watchTV() {// 重写watchTV()方法
System.out.println("我喜欢看电视");
}
@Override
public void cooking() {// 重写cook()方法
System.out.println("我喜欢做饭");
}
@Override
public void smoking() {// 重写smoke()方法
System.out.println("我喜欢抽烟");
}
@Override
public void goFishing() {// 重写goFishing()方法
System.out.println("我喜欢钓鱼");
}
public static void main(String[] args) {
IFather father = new H7_16();// 通过子类创建IFather接口对象
System.out.println("爸爸的爱好:");
// 使用接口对象调用子类中实现的方法
father.smoking();
father.goFishing();
IMather mather = new H7_16();// 通过子类创建IMather接口对象
System.out.println("\n妈妈的爱好:");
// 使用接口对象调用子类中实现的方法
mather.cooking();
mather.watchTV();
}
}
7.4.4 区分抽象类与接口
抽象类和接口都包含可以由子类继承实现的成员,但抽象类是对根源的抽象,而接口是对动抽象。抽象类的功能要远超过接口,那为什么还要使用接口呢?这主要是由于定义抽象类的个高(因为每个类只能继承一个类,在这个类中,必须继承或编写出其子类的所有共性,因此,虽然接口在功能上会弱化许多,但它只是针对一个动作的描述,而且可以在一个类中同时实现多个接这样会降低设计阶段的难度。
抽象类和接口的区别主要有以下几点。
(1)子类只能继承一个抽象类,但可以实现任意多个接口。
(2)一个类要实现一个接口必须实现接口中的所有方法,而抽象类不必。
(3)抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public static final 的(4)接口中只能定义抽象方法,而抽象类中可以定义非抽象方法。(5)抽象类中可以有静态方法和静态代码块等,接口中不可以。
(6)接口不能被实例化,没有构造方法,但抽象类可以有构造方法。
抽象类与接口的不同
7.5 访问控制
前面多次提到了public、private、包等关键字或者概念,这些都是用来控制类、方法或者变量的访问范围的,Java 中主要通过访问控制符、类包和final关键字对类、方法或者变量的访问范围行控制,本节将对Java中访问控制知识进行详细讲解
7.5.1 访问控制符
前面介绍了面向对象的几个基本特性,其中包括封装性,封装实际上有两方面的含义:把该隐藏的隐藏起来、把该暴露的暴露出来,这两个方面都需要通过使用Java 提供的“访问控制符”来实现,本节将对Java 中的访问控制符进行详细讲解。
Java 中的访问控制符主要包括 public、protected、private 和default(缺省)等4种,这些控制符控制着类和类的成员变量以及成员方法的访问权限。
Java语言中的访问控制符权限
使用访问控制符时,需要遵循以下原则。 (1)大部分顶级类都使用 public 修饰;
(2)如果某个类主要用作其他类的父类,该类中包含的大部分方法只是希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰;
(3)类中的绝大部分属性都应该使用private修饰,除非一些static或者类似全局变量的属性才考虑使用 public 修饰;
(4)当定义的方法只是用于辅助实现该类的其他方法(即工具方法),应该使用private 修(5)希望允许其他类自由调用的方法应该使用public 修饰。
7.5.2 Java 类包
在Java义好类,通Java编译器进行编译之后,都会生成一个扩展名为.class的文件,当这个程序的规模逐渐庞大时,就很容易发生类名称冲突的现象。那么JDKAPI中提供了成千上万具有各种功能的类,又是如何管理的呢?Java 中提供了一种管理类文件的机制,就是类包。
Java中每个接口或类都来自不同的类包,无论是JavaAPI中的类与接口还是自定义的类与接口都需要隶属于某一个类包,这个类包包含了一些类和接口。如果没有包的存在,管理程序中的类名称将是一件非常麻烦的事情,如果程序只由一个类定义组成,并不会给程序带来什么影响,但是随着程序代码的增多,难免会出现类同名的问题。例如,在程序中定义一个 Login 类,因业务需要,还要定义一个名称为Login的类,但是这两个类所实现的功能完全不同,于是问题就产生了,编译器不会允许存在同名的类文件。解决这类问题的办法是将这两个类放置在不同的类包中,实际上 Java中类的完整名称是包名与类名的组合。
7.5.3 final 关键字
定义为final的类不能被继承。
如果希望一个类不允许任何类继承,并且不允许其他人对这个类进行任何改动,可以将这个类设置为final形式。
final类的语法如下: final class类名{}
如果将某个类设置为final形式,则类中的所有方法都被隐式地设置为final形式,但是final 类中的成员变量可以被定义为final 或非 final形式。
代码
public final class H7_17 {
int a = 3;
void doit() {
}
public static void main(String args[]) {
H7_17 f = new H7_17();
f.a++;
System.out.println(f.a);
}
}
结果
代码
class Parents {
private final void doit() {
System.out.println("父类.doit()");
}
final void doit2() {
System.out.println("父类.doit2()");
}
public void doit3() {
System.out.println("父类.doit3()");
}
}
class Sub extends Parents {
public final void doit() { // 在子类中定义一个doit()方法
System.out.println("子类.doit()");
}
// final void doit2(){ //final方法不能覆盖
// System.out.println("子类.doit2()");
// }
public void doit3() {
System.out.println("子类.doit3()");
}
}
public class H7_18 {
public static void main(String[] args) {
Sub s = new Sub(); // 实例化
s.doit(); // 调用doit()方法
Parents p = s; // 执行向上转型操作
// p.doit(); //不能调用private方法
p.doit2();
p.doit3();
}
}
结果
代码
import static java.lang.System.out;
import java.util.Random;
class Test {
int i = 0;
}
public class H7_19 {
static Random rand = new Random();
private final int VALUE_1 = 9; // 声明一个final常量
private static final int VALUE_2 = 10; // 声明一个final、static常量
private final Test test = new Test(); // 声明一个final引用
private Test test2 = new Test(); // 声明一个不是final的引用
private final int[] a = { 1, 2, 3, 4, 5, 6 }; // 声明一个定义为final的数组
private final int i4 = rand.nextInt(20);
private static final int i5 = rand.nextInt(20);
public String toString() {
return i4 + " " + i5 + " ";
}
public static void main(String[] args) {
H7_19 data = new H7_19();
//data.test = new Test();
// 可以对指定为final的引用中的成员变量赋值
// 但不能将定义为final的引用指向其他引用
//data.value2++;
// 不能改变定义为final的常量值
data.test2 = new Test(); // 可以将没有定义为final的引用指向其他引用
for (int i = 0; i < data.a.length; i++) {
// a[i]=9;
// 不能对定义为final的数组赋值
}
out.println(data);
out.println("data2");
out.println(new H7_19());
out.println(data);
}
}
结果
代码
import java.util.Random;
import static java.lang.System.out;
public class H7_20 {
private static Random rand = new Random(); // 实例化一个Random类对象
// 随机产生0~10之间的随机数赋予定义为final的a1
private final int a1 = rand.nextInt(10);
// 随机产生0~10之间的随机数赋予定义为static final的a2
private static final int a2 = rand.nextInt(10);
public static void main(String[] args) {
H7_20 fdata = new H7_20(); // 实例化一个对象
// 调用定义为final的a1
out.println("重新实例化对象调用a1的值:" + fdata.a1);
// 调用定义为static final的a2
out.println("重新实例化对象调用a1的值:" + fdata.a2);
// 实例化另外一个对象
H7_20 fdata2 = new H7_20();
out.println("重新实例化对象调用a1的值:" + fdata2.a1);
out.println("重新实例化对象调用a2的值:" + fdata2.a2);
}
}
结果
7.6 内部类
7.6.1成员内部类
在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。本节首先介绍成员内部类。
成员内部类的语法如下:
public class OuterClass{//外部类
private class InnerClass{ //内部类 }} 在内部类中可以随意使用外部类的成员方法以及成员变量,尽管这些类成员被修饰为 private。图7.28充分说明了内部类的使用,尽管成员变量i以及成员方法g0都在外部类中被修饰为private但在内部类中可以直接使用外部类中的类成员。
代码
public class H7_21 {
innerClass in = new innerClass(); // 在外部类实例化内部类对象引用
public void ouf() {
in.inf(); // 在外部类方法中调用内部类方法
}
class innerClass {
innerClass() { // 内部类构造方法
}
public void inf() { // 内部类成员方法
}
int y = 0; // 定义内部类成员变量
}
public innerClass doit() { // 外部类方法,返回值为内部类引用
// y=4; //外部类不可以直接访问内部类成员变量
in.y = 4;
return new innerClass(); // 返回内部类引用
}
public static void main(String args[]) {
H7_21 out = new H7_21();
// 内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现
H7_21.innerClass in = out.doit();
H7_21.innerClass in2 = out.new innerClass();
}
}
代码
interface OutInterface { // 定义一个接口
public void f();
}
public class H7_22 {
public static void main(String args[]) {
OuterClass2 out = new OuterClass2 (); // 实例化一个OuterClass2对象
// 调用doit()方法,返回一个OutInterface接口
OutInterface outinter = out.doit();
outinter.f(); // 调用f()方法
}
}
class OuterClass2 {
// 定义一个内部类实现OutInterface接口
private class InnerClass implements OutInterface {
InnerClass(String s) { // 内部类构造方法
System.out.println(s);
}
public void f() { // 实现接口中的f()方法
System.out.println("访问内部类中的f()方法");
}
}
public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口
return new InnerClass("访问内部类构造方法");
}
}
结果
代码
public class H7_23 {
private int x;
private class Inner {
private int x = 9;
public void doit(int x) {
x++; //调用的是形参x
this.x++; //调用内部类的变量x
H7_23.this.x++; //调用外部类的变量x
}
}
}
结果
7.6.2 局部内部类
内部类不仅可以在类中进行定义,也可以在类的局部位置定义如在类的方法或任意的作用域中均可以定义内部类
代码
public interface H7_24 {
}
class OuterClass3 {
public H7_24 doit(final String x) { // doit()方法参数为final类型
// 在doit()方法中定义一个内部类
class InnerClass2 implements H7_24 {
InnerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
结果
7.6.3 匿名内部类
代码
public interface H7_25 {
}
class OuterClass4 {
public H7_25 doit() { // 定义doit()方法
return new H7_25() { // 声明匿名内部类
private int i = 0;
public int getValue() {
return i;
}
};
}
}
使用匿名内部类时应该遵循以下原则:(1)匿名类没有构造方法;
(2)匿名类不能定义静态的成员;
(3)匿名类不能用private、public、protected、static、final、abstract 等修饰; (4)只可以创建一个匿名类实例。
7.6.4 静态内部类
可以这样认为,普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象但如果内部类被定义为static,就会有更多的限制。静态内部类具有以下两个特点:
(1)如果创建静态内部类的对象,不需要创建其外部类的对象;
(2)不能从静态内部类的对象中访问非静态外部类的对象。
代码
public class H7_26 {
int x = 100;
static class Inner {
void doitInner() {
// System.out.println("外部类"+x);
}
public static void main(String args[]) {
System.out.println();
}
}
}
7.6.5 内部类的继承
内部类和其他普通类一样可以被继承,但是继承内部类比继承普通类复杂,需要设置专门的语法来完成。
代码
public class H7_27 extends ClassA.ClassB { // 继承内部类ClassB
public H7_27(ClassA a) {
a.super();
}
}
class ClassA {
class ClassB {
}
}