Java面向对象——内部类(成员内部类、静态内部类、局部内部类、匿名内部类,完整详解附有代码+案例)
文章目录
- 内部类
- 17.1概述
- 17.2成员内部类
- 17.2.1 获取成员内部类对象
- 17.2.2 成员内部类内存图
- 17.3静态内部类
- 17.4局部内部类
- 17.5匿名内部类
- 17.5.1概述
内部类
17.1概述
写在一个类里面的类叫内部类,即 在一个类的里面再定义一个类。
如,A类的里面的定义B类,B类就称内部类
public class A{
public class B{
}
}
内部类表示的事物是外部类的一部分
内部类单独出现没有任何意义
什么时候用到内部类?
B类表示的事物是A类的一部分,且B单独存在没有意义
如:汽车的发动机,ArrayList的迭代器,人的心脏等等
内部类的访问特点:
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须要创建对象
内部类案列:
需求:写一个JavaBean类描述汽车
属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限。
public class Car {//Car类是外部类
private String carName;
int carAge;
String carColor;
public void show(){
System.out.println(carName);//null
System.out.println(carAge);//1
// 外部类要访问内部类的成员,必须要创建对象
Engine e = new Engine();
e.engineName="比亚迪";
System.out.println(e.engineName);//比亚迪
}
class Engine{//Engine类是内部类
String engineName;
int engineAge;
}
}
============================================
public class Test {
public static void main(String[] args) {
Car car = new Car();
car.carAge=1;
car.carColor="黑色";
car.show();
//null 1 比亚迪
}
}
17.2成员内部类
写在成员位置,属于外部类成员
成员内部类可以被一些修饰符所修饰,比如: private,默认,protected,public,static等
在成员内部类里面,JDK16之前不能定义静态变量,JDK16开始才可以定义静态变量。
public class Car {//Car类是外部类
private String carName;
int carAge;
String carColor;
class Engine{//Engine类是成员内部类
String engineName;
int engineAge;
}
}
17.2.1 获取成员内部类对象
方式一:外部直接创建成员内部类的对象
格式:外部类.内部类 变量 = new 外部类().new 内部类();
public class Outer {
// 成员内部类,属于外部类对象的。
// 拓展:JDK16之前成员内部类不能定义静态成员。
public class Inner{
// 这里面的东西与类是完全一样的。
public void method(){
System.out.println("内部类中的方法被调用了");
}
}
}
========================================================
public class Test {
public static void main(String[] args) {
// 宿主:外部类对象。
// Outer out = new Outer();
// 创建内部类对象。
//方式一:外部直接创建成员内部类的对象
Outer.Inner oi = new Outer().new Inner();
oi.method();
}
}
方式二:在外部类中定义一个方法提供内部类的对象(内部类是私有的)
public class Outer {
String name;
private class Inner{
static int a = 10;
}
//在外部类中定义一个方法提供内部类的对象
public Inner getInstance(){
return new Inner();
}
}
==================================
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
//第一种接收
//Object o = o.getInstance()
//第二种,直接打印
System.out.println(o.getInstance());
}
}
17.2.2 成员内部类内存图
public class Outer {
private int a = 10;
class Inner {
private int a = 20;
public void show() {
int a = 30;
//Outer.this 获取了外部类对象的地址值
System.out.println(Outer.this.a);//10
System.out.println(this.a); //20
System.out.println(a); //30
}
}
}
============================================================
public class Test {
public static void main(String[] args) {
//创建内部类的对象,并调用show方法
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
(图片来自B站Java视频)
17.3静态内部类
成员内部类的一种
public class Car {//Car类是外部类
private String carName;
int carAge;
String carColor;
static class Engine{//Engine类是静态内部类
String engineName;
int engineAge;
}
}
- 静态内部类可以直接访问外部类的静态变量和静态方法。
- 静态内部类不可以直接访问外部类的非静态成员,如果要访问需要创建外部类的对象。
静态内部类对象的创建格式:
外部类名.内部类名 对象名 = new 外部类名.内部类名();
调用方法的格式:
- 调用非静态方法的格式:先创建对象,用对象调用
- 调用静态方法的格式:外部类名.内部类名.方法名();
案例:
public class Outer {
int a = 6;
static int b = 8;
//静态内部类
static class Inner {
public void show1(){
// 静态内部类可以直接访问外部类的静态变量
System.out.println(b);
// 如果访问外部类非静态,需要先创建外部类对象
Outer o = new Outer();
System.out.println(o.a);
System.out.println("非静态的方法被调用了");
}
public static void show2(){
System.out.println("静态的方法被调用了");
}
}
}
=====================================
public class Test {
public static void main(String[] args) {
// 调用非静态方法需要,先创建对象,再用对象调
Outer.Inner oi = new Outer.Inner();
oi.show1();// 8 6 非静态的方法被调用了
// 静态方法用类名直接调用
Outer.Inner.show2();
//调用内部类中的静态方法,用内部类名调也可以
oi.show2();
}
}
17.4局部内部类
- 将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
- 外界是无法直接使用局部内部类,需要在方法内部创建对象并使用。
- 该类可以直接访问外部类的成员,也可以访问方法内的局部变量。
public class Outer {
int b = 20;
public void show(){
int a = 10;
//局部内部类
class Inner{
String name;
int age;
public void method1(){
System.out.println(a);
System.out.println(b);
System.out.println("局部内部类method1方法");
}
public static void method2(){
System.out.println("局部内部类method2静态方法");
}
}
//(在show方法中)创建局部内部类的对象
Inner i = new Inner();
System.out.println(i.name);
System.out.println(i.age);
i.method1();
Inner.method2();
}
}
==============
public class Test {
public static void main(String[] args) {
/*
局部内部类
1.将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。
2.外界是无法直接使用局部内部类,需要在方法内部创建对象并使用。
3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量。*/
//调用show方法,让代码执行
Outer o = new Outer();
o.show();
//输出:null 0 10 20 局部内部类method1方法
// 局部内部类method2静态方法
}
}
17.5匿名内部类
使用场景:
- 当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象。
- 如果实现类只要使用一次,可以用匿名内部类简化代码。
17.5.1概述
匿名内部类本质就是隐藏了名字的内部类。
匿名内部类的格式:
此格式整体就是一个类的子类对象或者接口的实现类对象
new 类名或者接口名(){
重写方法;
};
如:new Animal(){
@Override
public void eat() {
System.out.println("重写了eat方法...");
}
};
此格式包含三部分:
继承(类)/实现(接口) 方法重写 创建对象
实际上:
匿名内部类指的是:
{
重写方法;
};
而匿名内部类的对象指的是:
new 类名或者接口名(){
重写方法;
};
以前:
//父类
public abstract class Animal {
public abstract void eat();
}
============================================
//子类
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗在吃东西...");
}
}
============================================
//测试类
public static void main(String[] args) {
/*
在测试类中调用下面的method方法?
以前的方式如何调用?
要自己写一个子类继承Animal类
再创建子类的对象,传递给method方法
*/
//第一种方式调用method
Dog dog = new Dog();
method(dog); //输出:狗在吃东西...
//如果Dog类我只要用一次,那么还需要单独定义一个类太麻烦了。
}
//定义方法
public static void method(Animal a){//Animal a = 子对象 ->多态
a.eat();//执行看左边,编译看右边
}
}
现在:无需创建子类…
public abstract class Animal {
public abstract void eat();
}
============================================
public class Test {
public static void main(String[] args) {
method(
new Animal() {
@Override
public void eat() {
System.out.println("小黑在吃东西...");
}
}
);
}
//定义方法
public static void method(Animal a){
a.eat();
}
}
接口多态
public interface Swim {
public abstract void swim();
}
===========================================
public class Test02 {
public static void main(String[] args) {
//接口多态
Swim s = new Swim() {
@Override
public void swim() {
System.out.println("重写swim接口的方法...");
}
};
s.swim();
}
}
public interface Swim {
public abstract void swim();
}
===========================================
public class Test02 {
public static void main(String[] args) {
//接口多态
Swim s = new Swim() {
@Override
public void swim() {
System.out.println("重写swim接口的方法...");
}
};
s.swim();
}
}