class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
这些内部类被称为嵌套。它们分为两种类型:
- 非静态嵌套类。这些也称为内部类。
- 静态嵌套类。
- 本地班级
- 匿名类
public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
我们在这里上课Bicycle
。它有 2 个字段和 1 个方法:start()
. 它与普通类的不同之处在于它包含两个类:Handlebar
和Seat
。他们的代码写在Bicycle
类里面。这些是成熟的类:如您所见,每个类都有自己的方法。说到这里,您可能会有一个疑问:为什么我们要把一个类放在另一个类中?为什么要让它们成为内部类?好吧,假设我们需要单独的类来处理程序中的把手和座椅的概念。当然,我们没有必要让它们嵌套!我们可以做普通班。例如,像这样:
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
很好的问题!当然,我们不受技术的限制。这样做当然是一种选择。在这里,更重要的是从特定程序及其目的的角度正确设计类。内部类用于分离出与另一个实体密不可分的实体。车把、车座和踏板是自行车的组成部分。与自行车分开,它们没有多大意义。如果我们将所有这些概念单独的公共类,我们的程序中就会有这样的代码:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
嗯……这段代码的意思就更难解释了。我们有一些模糊的车把(为什么有必要?老实说,不知道)。这个把手向右转……完全靠自己,没有自行车……出于某种原因。通过将车把的概念与自行车的概念分开,我们在程序中丢失了一些逻辑。使用内部类,代码看起来非常不同:
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.Handlebar handlebar = peugeot.new Handlebar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handlebar.left();
handlebar.right();
}
}
控制台输出:
Seat up!
Let's go!
Steer left!
Steer right!
现在我们所看到的突然变得有道理了!:) 我们创建了一个自行车对象。我们创建了两个自行车“子对象”——一个把手和一个座椅。为了舒适起见,我们将座椅抬高,然后出发:根据需要踩踏板和转向!:) 我们需要的方法在适当的对象上被调用。一切都简单方便。在此示例中,将车把和座椅分开可增强封装(我们将有关自行车零件的数据隐藏在相关类中)并让我们创建更详细的抽象。现在让我们看看不同的情况。假设我们要创建一个模拟自行车商店和自行车备件的程序。 在这种情况下,我们之前的解决方案将行不通。在自行车商店,每个单独的自行车零件即使与自行车分开也是有意义的。例如,我们将需要“向客户出售踏板”、“购买新座椅”等方法。在这里使用内部类是错误的——我们新程序中的每个自行车零件都具有代表意义其自身:可以脱离自行车的概念。如果您想知道是应该使用内部类还是将所有实体组织为单独的类,那么这正是您需要注意的。面向对象编程的好处在于它可以轻松地对真实世界的实体进行建模。在决定是否使用内部类时,这可能是您的指导原则。在实体店里,备件与自行车分开——这没关系。也就是说在设计程序的时候也是可以的。好的,我们已经了解了“哲学”:) 现在让我们熟悉内部类的重要“技术”特性。以下是您绝对需要记住和理解的内容:
-
没有外部类的对象,内部类的对象就不能存在。
这是有道理的:这就是我们在程序中创建内部类
Seat
和Handlebar
内部类的原因——这样我们就不会得到孤立的车把和座椅。此代码无法编译:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
另一个重要特征由此而来:
-
内部类的对象可以访问外部类的变量。
例如,让我们
int seatPostDiameter
在我们的类中添加一个变量(代表座杆的直径)Bicycle
。然后在
Seat
内部类中,我们可以创建一个displaySeatProperties()
显示座位属性的方法:public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
现在我们可以在我们的程序中显示这些信息:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
控制台输出:
Seat properties: seatpost diameter = 40
笔记:新变量使用最严格的访问修饰符 ( ) 声明
private
。而且内部类仍然可以访问! -
不能在外部类的静态方法中创建内部类的对象。
这可以通过内部类的组织方式的具体特征来解释。内部类可以有带参数的构造函数,或者只有默认构造函数。但无论如何,当我们创建一个内部类的对象时,外部类对象的引用无形中传递给了内部类创建的对象。毕竟,存在这样一个对象引用是绝对必要的。否则,我们将无法创建内部类的对象。
但是如果外部类的方法是静态的,那么我们可能没有外部类的对象!这将违反内部类如何工作的逻辑。在这种情况下,编译器会产生一个错误:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
内部类不能包含静态变量和方法。
逻辑是一样的:即使没有对象,静态方法和变量也可以存在并被调用或引用。
但是如果没有外部类的对象,我们将无法访问内部类。
明显的矛盾!这就是内部类中不允许使用静态变量和方法的原因。
如果您尝试创建它们,编译器将生成错误:
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
创建内部类的对象时,其访问修饰符很重要。
可以使用标准访问修饰符标记内部类:
public
、private
、protected
和package private
。为什么这很重要?
这会影响我们可以在程序中创建内部类实例的位置。
如果我们的
Seat
类声明为public
,我们可以在任何其他类中创建Seat
对象。唯一的要求是外部类的对象也必须存在。顺便说一句,我们已经在这里做了:
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.Handlebar handlebar = peugeot.new Handlebar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handlebar.left(); handlebar.right(); } }
我们很容易
Handlebar
从Main
类中获得了对内部类的访问权限。如果我们将内部类声明为
private
,我们将只能在外部类中创建对象。我们不能再
Seat
“在外面”创建一个对象:private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
您可能已经理解其中的逻辑 :)
-
内部类的访问修饰符与普通变量的工作方式相同。
修饰符
protected
提供对同一包中的子类和类中的实例变量的访问。protected
也适用于内部类。我们可以创建protected
内部类的对象:- 在外部类;
- 在其子类中;
- 在同一个包中的类中。
如果内部类没有访问修饰符(
package private
),则可以创建内部类的对象:- 在外部类;
- 在同一个包中的类中。
您已经熟悉修饰符很长时间了,所以这里没有问题。
GO TO FULL VERSION