引入
创建内部类
- 在一些项目需求中,会出现一个类中的属性还有其他属性的情况,比如:
- 对于餐馆类,通常会有的属性有餐馆的名字,餐馆的地址,餐馆的菜单,但对于菜单来说,其内部又有菜名,价格,辣度等属性
- 面对怎样的需求,就可以建立一个Restaurant餐馆类,在Restaurant类中再创建一个MenuItem内部类,如下方代码所示:
package com.inside;
public class Restaurant {
private String name;
private String address;
public Restaurant() {}
public void CreateMenuItem(String name,double price){
MenuItem menuItem = new MenuItem(name,price);
}
public static class MenuItem{
private String name;
private double price;
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
@Override
public String toString() {
return "Restaurant{" +
"name='" + name + ''' +
", address='" + address + ''' +
'}';
}
public static void main(String[] args) {
Restaurant restaurant = new Restaurant();
}
}
在外层类中使用内部
- 在外部类中,必须通过外部类示例化对象类访问内部类的属性和方法,如下方代码中的test方法,一些版本的JDK甚至允许使用
内部类对象.属性的方式来访问内部类中的私有化属性
public class Restaurant {
public static class MenuItem{
private String name;
private double price;
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
public void test(){
MenuItem rice = new MenuItem("java炒饭",12.0);
String foodName = rice.name;
System.out.println(foodName);
String foodName1 = rice.getName();
System.out.println(foodName1);
}
public static void main(String[] args) {
Restaurant restaurant = new Restaurant();
restaurant.test();
}
}
内部类的修饰符
Public Static
- 在创建内部类的时候,最好使用static进行修饰,这样才可以在外层类中访问该内部类,因为如果没有使用static进行修饰,内部类并不是属于外层类的,而是属于外部类实例化的对象的属性类,类似于静态方法和成员方法的区别
public
- 当没有使用static 修饰内部类,则需要使用外层类的示例化对象访问内部类,类似于成员方法,如下方代码所示,我们只使用public修饰内部类:
package com.inside;
public class Restaurant {
private String name;
private String address;
public Restaurant() {}
public void CreateMenuItem(String name,double price){
MenuItem menuItem = new MenuItem(name,price);
}
public class MenuItem{
private String name;
private double price;
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
public static void main(String[] args) {
}
}
- 只用public修饰,当我们在其他类中访问Restaurant.MenuItem则要通过外层类的示例化对象, 测试用例如下方代码所示:
package com.inside;
public class RestaurantMain {
public static void main(String[] args) {
Restaurant restaurant = new Restaurant();
Restaurant.MenuItem menuItem = restaurant.new MenuItem("python炒面",10);
}
}
private
- 当我们使用private修饰内部类的时候则在外层类和通过外层类对象就都无法访问了,这时候我们就要在外层类中创建一个方法类管理内部类:
- 这里我们将内部类用private修饰内部类,并创建管理内部类MenuItem的方法CreateMenuItem(),如下方代码所示:
public class Restaurant {
private String name;
private String address;
public Restaurant() {}
public void CreateMenuItem(String name,double price){
MenuItem menuItem = new MenuItem(name,price);
}
private class MenuItem{
private String name;
private double price;
public MenuItem(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
}
}
函数内部类(局部内部类)
package com.inside;
public class Restaurant {
private String name;
private String address;
public Restaurant() {}
public void showSpicy(String spicy){
class LocalClass{
public void display(){
System.out.println("辣度是" + spicy);
}
}
LocalClass spicyObject = new LocalClass();
spicyObject.display();
}
}
package com.inside;
public class RestaurantMain {
public static void main(String[] args) {
restaurant.showSpicy("特辣");
}
}
匿名内部类
什么是匿名内部
- 匿名内部类是一种特殊的局部内部类;所谓匿名:指的是不需要为这个类声明名字。
匿名内部类的格式
new 抽象类名/接口名(){
重写抽象类名或者接口中的抽象方法等
};
匿名内部类的特点
- 匿名内部类的本质就是在外层类中一个会立刻创建对象的类,一般是其他接口或抽象方法的实现类。
匿名内部类例
interface Swimming{
public abstract void swim();
}
- 按照正常步骤如果我们需要使用接口就要先实现接口,然后实例化实现类,将实现类的对象传入需要接口实现类实例化对象的方法中像这样:
class swimmingImpl implements Swimming{
@Override
public void swim() {
System.out.println("我们去游泳了...");
}
}
public class Test1{
public static void main(String[] args){
useSwimming(new swimmingImpl());
}
public static void useSwimming(Swimming swimming){
swimming.swim();
}
}
- 但其实,有了匿名内部类,我们可以将实现接口的swimmingImpl实现类和调用需要实现类对象的useSwimming方法合并,如下方代码所示:
public class Test1{
public static void main(String[] args){
useSwimming(new swimmingImpl());
useSwimming(new Swimming() {
@Override
public void swim() {
System.out.println("我是在Test1中的匿名内部类,我要去游泳了");
}
});
}
vpublic static void useSwimming(Swimming swimming){
swimming.swim();
}
}
- 有时候我们可能会想向匿名内部类中写入一些不是用于实现接口的方法,也就是只是内部类的方法,那我们调用就只可以在内部类末尾使用
.方法名()的方式调用
public class Test1{
public static void main(String[] args){
new Swimming() {
@Override
public void swim() {
System.out.println("我是在Test1中的匿名内部类,我要去游泳了");
}
public void test(){
System.out.println("我是匿名内部类中的特殊方法");
}
}.test();
}
public static void useSwimming(Swimming swimming){
swimming.swim();
}
}
应用场景
- 通常来说当一个方法的参数只需要一个接口的实现对象,而且这个实现对象在可以未来遇见的开发中只使用这一次
- 例如匿名内部类通常用于实现接口或继承其他类,并立即创建该类的对象;使用匿名内部类创建线程
- 常用于线程、事件监听器等场景。
总结
- 内部类可以更好的帮我们封装或者组织代码,对于属性中还有属性的需求,我们可以通过内部类将需求拆分为类中的内部类
- 根据修饰符的不同内部类也可以分多种
- public : 成员内部类
- public static: 静态成员内部类
- private:私有内部类
- Class.func.Class -- 即为函数中的内部类:局部内部类
- 外层的类想要访问内部类中的属性和方法,只能通过内部类的实例化对象
- 在外层类之外的类,根据属性的不同访问的方式也不同
- public (成员内部类):通过外层类的实例化对象进行访问
- public static( 静态成员内部类):直接通过外层类访问
- private(私有内部类):除了外层类,其他类无法访问,在外层类编写管理内部类的函数
- Class.func.Class -- 即为函数中的内部类(局部内部类): 通过调用函数访问