欢迎光临
我们一直在努力

Java类与对象

前言

本人的技术笔记会优先发布在个人站点longyxblg.cn

面向对象

在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。

面向对象与面向过程

一个比较经典的问题————将大象装进冰箱里

面向过程的思想,需要考虑怎么打开冰箱门,如何规划空间,如何关上门…等诸多步骤

面向对象的思想,就简单多了。

  • 打开冰箱门

  • 放进大象

  • 关闭冰箱门

至于中间的诸多操作,不需要考虑。都是通过对象之间的交互来完成的。

类

类是用来描述一个实体(对象)的

类的定义

在java中定义类时需要用到class关键字,具体语法如下

class ClassName{
field;// 字段(属性) 或者 成员变量
method;// 行为或者成员方法
}

class为定义类的关键字,ClassName为类的名字,{}中为类的主体类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。


这里来定义一个 Dog 类,需要注意的是:

  • 类名注意采用大驼峰定义

  • 成员前写法统一为public,具体原因会在后文解释

  • 此处写的方法都不带 static , 具体原因会在后文解释

在 Java 中,建议一个 java 文件中只存在一个类。public 修饰的类必须与文件名相同。

public class Dog {
String name;
int age;

public void eat(){
System.out.println(name+"吃狗粮!");
}

public void bark(){
System.out.println(name + "正在汪汪汪!");
}
}

类的定义格式上有点类似于 C 语言中的结构体。

这里就写了一个简单的 Dog 类。

类的实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与 int,double 类似,只不过 int和 double 是 java 语言自带的内置类型,而类是用户自定义了一个新的类型,比如上文定义的 Dog 类。

用类类型创建对象的过程被称为实例化,在 Java 中采用 new 关键字配合类型来实例化对象。

Dog dog = new Dog();

这样就实例化了一个 Dog 类型的对象。个人对类与对象的理解是:类是模具,对象是通过模具生产出来的具体产品,同一个模具生产出来的产品都符合产品的统一规格,但也可以有自己的细微差异。

访问一个对象中的成员需要用到 .

对象的成员在没有初始化时, 基本数据类型的值默认为 0 , 引用数据类型的值默认为 null

Dog dog1 = new Dog();
System.out.println(dog1.age);
System.out.println(dog1.name);

在这里插入图片描述

Dog dog = new Dog();
dog.age = 5;
dog.name = "大黄";
dog.bark();
dog.eat();

在这里插入图片描述

同一个类型可以实例化多个对象

Dog dog = new Dog();
dog.age = 5;
dog.name = "大黄";
dog.bark();
dog.eat();

// 同一个类可以实例化多个对象
Dog dog2 = new Dog();
dog.age = 3;
dog.name = "旺财";
dog.bark();
dog.eat();

在这里插入图片描述

  • 类只是一个模型一样的东西,用来对一个实体进行描述,限定了实体有哪些成员

  • 类是一种自定义的类型,可以用来定义变量

  • 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

this 引用

定义一个 Cat 类

public class Cat {
String name;
int age;

public void SetCat(int age,String name){
age = age;
name = name;
}
}

Cat cat1 = new Cat();
cat1.SetCat(1,"哈吉米");
System.out.println(cat1.age);
System.out.println(cat1.name);

在这里插入图片描述

可以看到赋值当形参名和对象成员变量名相同时,赋值并没有成功,这是就可以用到 this 。

public class Cat {
String name;
int age;

public void SetCat(int age,String name){
// 使用 this 就可以成功赋值
this.age = age;
this.name = name;
}
}

Cat cat1 = new Cat();
cat1.SetCat(1,"哈吉米");
System.out.println(cat1.age);
System.out.println(cat1.name);

在这里插入图片描述


this 引用指向的是当前对象,即谁调用这个方法, this 就指向谁。

在这里插入图片描述

通过调试可以看到 this 和 cat1 这两个对象引用的是同一个地址。

this 引用的特性

  • this 只能在成员方法中使用

在这里插入图片描述

  • 在"成员方法"中,this 只能引用当前对象,不能再引用其他对象

  • this 实际是成员方法的第一个参数,当设计者没有写这个参数时,编译器会隐藏式的补上。编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this 负责来接收。

在这里插入图片描述

构造方法

上文中的 Dog 和 Cat 类,在对对象初始化时,要么用 .成员名进行赋值 , 要么写一个方法然后用对象调用这个方法,很麻烦。

Java 中为类提供了一个成员方法被称为构造方法。

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次。

public class Cat {
String name;
int age;

public void SetCat(Cat this,int age,String name){
// 使用 this 就可以成功赋值
this.age = age;
this.name = name;
}

public Cat(){
System.out.println("调用了构造方法");
}

public void Eat(){
System.out.println(this.name + "正在吃小鱼干");
}

public void Speak(){
System.out.println(this.name + "正在喵喵叫");
}
}

Cat cat1 = new Cat();
cat1.SetCat(1,"哈吉米");
System.out.println(cat1.age);
System.out.println(cat1.name);

这个构造方法是可以重载的

public class Cat {
String name;
int age;

public void SetCat(Cat this,int age,String name){
// 使用 this 就可以成功赋值
this.age = age;
this.name = name;
}

public Cat(){
System.out.println("调用了构造方法");
}

public Cat(int age , String name){
this.age = age;
this.name = name;
System.out.println("调用了带参数的构造方法");
}

public void Eat(){
System.out.println(this.name + "正在吃小鱼干");
}

public void Speak(){
System.out.println(this.name + "正在喵喵叫");
}

}

Cat cat1 = new Cat(1,"咪咪");
System.out.println(cat1.age);
System.out.println(cat1.name);

在这里插入图片描述

需要注意的是

  • 构造方法名字必须与类名相同

  • 没有返回值类型,设置为void也不行

在这里插入图片描述

  • 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次

Cat cat1 = new Cat(1,"咪咪");
System.out.println(cat1.age);
System.out.println(cat1.name);
// 构造方法只能在创建对象时调用,并且只能使用一次
cat1.Cat();

在这里插入图片描述

  • 如果用户没有显式定义,编译器会生成一份默认的构造方法,生成的默认构造方法一定是无参的。所以在前文中没有显示定义构造方法时,可以直接

Cat cat = new Cat();
Dog dog = new Dog();

  • 一旦显示定义,编译器不再主动生成

public class Student {
int age;
String name;
String gender;

public Student(String gender, String name, int age) {
// 一旦显示定义,编译器不再主动生成
this.gender = gender;
this.name = name;
this.age = age;
}
}

在这里插入图片描述

  • 构造方法中,可以通过this调用其他构造方法来简化代码

public class Student {
int age;
String name;
String gender;

public Student() {
// 构造方法中,可以通过this调用其他构造方法来简化代码
this("male","默认名称",18);
}

public Student(String gender, String name, int age) {
// 一旦显示定义,编译器不再主动生成
this.gender = gender;
this.name = name;
this.age = age;
}

public static void main(String[] args) {
// 一旦显示定义,编译器不再主动生成
Student stu = new Student();
System.out.println(stu.gender);
System.out.println(stu.age);
System.out.println(stu.name);
}

在这里插入图片描述

  • 构造方法不能形成环

在这里插入图片描述

就地初始化

在声明成员变量时,就直接给出了初始值

public class Book {
// 就地初始化
String Book_Name = "《西游记》";
String author = "吴承恩";
double price = 13.14;

public Book(){

}

public Book(String Book_Name,String author,double price){
this.Book_Name = Book_Name;
this.author = author;
this.price = price;
}
}

public static void main(String[] args) {
Book book1 = new Book();
System.out.println(book1.Book_Name);
System.out.println(book1.author);
System.out.println(book1.price);

Book book2 = new Book("《三体》","刘慈欣",5.20);
System.out.println(book2.Book_Name);
System.out.println(book2.author);
System.out.println(book2.price);
}

在这里插入图片描述

封装

面向对象程序三大特性:封装、继承、多态。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节。

例如,手机可以打电话、发消息、移动支付…等诸多功能,人们可以使用这些功能,但不知道他具体是怎么操作的。这就是因为手机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、屏幕等,让人们可以和手机进行交互。这就是一种封装。

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

访问修饰限定符

Java中主要通过类和访问权限来实现封装:类可以将数据以及封装数据的方法结合在一起,而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符:

名称同一个包同类同一个包不同类不同包中子类不同包中的非子类
public √ √ √ √
protected √ √ √
default √ √
private √

protected 主要用在继承中,会在继承中详细解释。

public 修饰代表着任何地方都可以使用

private 和 default 会使访问受限:

封装扩展包

在面向对象体系中,提出了一个软件包的概念,即:为了更好的管理类,把多个类收集在一起成为一组,称为软件包。其本质就是文件夹。

包是对类、接口等的封装机制的体现,是一种对类或者接口等的很好的组织方式,例如

java.util.Arrays

其中 java.util 就是一个包, Arrays 是 util 中的一个类

导入包中的类

int[] arr = new int[]{1,2,3};
System.out.println(java.util.Arrays.toString(arr));

在这里插入图片描述

这样写虽然可以但是太麻烦了

通常还是选择导入这个包中的类

import java.util.Arrays

int[] arr = new int[]{1,2,3};
// 通常还是选择导入对应的类
System.out.println(Arrays.toString(arr));

如果想使用 java.util 中包含的所有类,可以用 *

import java.util.*

更建议显式的指定要导入的类名. 否则容易出现冲突

import java.util.*;
import java.sql.*;

]在这里插入图片描述

由于 util 和 sql 两个包中都粗壮乃 Date 类,JVM 就分不清楚到底要使用哪个类

在这种情况下要指定使用的类

在这里插入图片描述

可以使用import static 导入包中静态的方法和字段。

import static java.lang.System.*;

int[] arr = new int[]{1,2,3};
out.println(arr[0]);

在这里插入图片描述

自定义包

在 IntelliJ IDEA 2026 中,右击文件右击新建可以找到新建包

在这里插入图片描述

这里新建一个包叫 Demo , 在 Demo 包下新建一个 Cat 类

在这里插入图片描述

可以看到 Cat 类上有一个 package Demo

访问修饰限定符的作用

此时在 Demo 包下再创建一个 Dog 类

在这里插入图片描述

public class Cat {

// 不写访问修饰限定符,默认就为 default 的操作权限
int age;
String name;

public Cat(int age, String name) {
this.age = age;
this.name = name;
}

public static void main(String[] args) {
// Dog 和 Cat 类在 Demo 包下
// 所以在 Cat 的 main 方法中可以通过 . 操作 Dog 类对象的成员
Dog dog = new Dog(1,"大黄");
System.out.println(dog.age);
System.out.println(dog.name);
}

}

package Demo;

public class Dog {
// 不写访问修饰限定符,默认就为 default 的操作权限

int age;
String name;

public Dog(int age, String name) {
this.age = age;
this.name = name;
}

public void bark(){
System.out.println(this.name + "正在汪汪叫");
}
}

在这里插入图片描述

这里 Cat 类中是可以直接操作 Dog 类对象的成员变量和方法的。

此时,有一 Test 类与 Demo 包平级。

在这里插入图片描述

在 Test 类中有如下代码

Dog dog = new Dog(1,"旺财");
System.out.println(dog.age);
System.out.println(dog.name);

运行结果如下

在这里插入图片描述

这就是因为 default 的权限限制, Test 包与 Demo 包是平级关系,Test 包中无权访问 Demo 包中 default 修饰的成员


再来看看 private , 在 Demo 包下再定义一个 Book 类和一个 Student 类

在这里插入图片描述

package Demo;

public class Student {
private int age;

private String name;

private String id;

public Student(String name, String id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
}

package Demo;

public class Book {
String book_Name;

String author;

double price;

public Book(String book_Name, String author, double price) {
this.book_Name = book_Name;
this.author = author;
this.price = price;
}

public static void main(String[] args) {
Student stu1 = new Student("张三","10086",18);
System.out.println(stu1.name);
System.out.println(stu1.id);
System.out.println(stu1.age);
}
}

在这里插入图片描述

private 修饰符,同一包下不同子类也操作对象被 private 修饰的成员变量。这就起到了一个封装的作用,只知道可以调用,但是不知道具体的操作过程。


如果确实需要查看 Student 的成员变量, 那么可以在 Student 类中定义对应的成员方法。通常名称为 get 。

package Demo;

public class Student {
private int age;

private String name;

private String id;

public Student(String name, String id, int age) {
this.name = name;
this.id = id;
this.age = age;
}

public int getAge() {
return age;
}

public String getName() {
return name;
}

public String getId() {
return id;
}
}

package Demo;

public class Book {
String book_Name;

String author;

double price;

public Book(String book_Name, String author, double price) {
this.book_Name = book_Name;
this.author = author;
this.price = price;
}

public static void main(String[] args) {
Student stu1 = new Student("李四","123",18);
System.out.println(stu1.getAge());
System.out.println(stu1.getId());
System.out.println(stu1.getName());
}
}

在这里插入图片描述

static 修饰成员变量

static 修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。

package Demo;

public class Student {
private int age;

private String name;

private String id;

// static 修饰的成员变量与方法, 不需要依赖对象就能使用
public static String classRoom = "三年一班";

public Student(String name, String id, int age) {
this.name = name;
this.id = id;
this.age = age;
}

public int getAge() {
return age;
}

public String getName() {
return name;
}

public String getId() {
return id;
}
}

在 Student 类中写下如下 main 方法

public static void main(String[] args) {
System.out.println(Student.classRoom);
Student stu1 = new Student("张三","123",18);
Student stu2 = new Student("李四","456",18);
Student stu3 = new Student("王五","789",18);
System.out.println(stu1.classRoom);
System.out.println(stu2.classRoom);
System.out.println(stu3.classRoom);
}

!在这里插入图片描述

这个被 static 修饰的 classRoom 不需要依赖对象也能够使用。

Student stu1 = new Student("张三","123",18);
Student stu2 = new Student("李四","456",18);
Student stu3 = new Student("王五","789",18);
stu1.classRoom = "三年二班";
// 通过对象修改和通过类修改都能修改这个成员变量的值
System.out.println(stu1.classRoom);
System.out.println(stu2.classRoom);
System.out.println(stu3.classRoom);
System.out.println(Student.classRoom);

Student.classRoom = "三年三班";
System.out.println("我是一条分割线");
System.out.println(stu1.classRoom);
System.out.println(stu2.classRoom);
System.out.println(stu3.classRoom);
System.out.println(Student.classRoom);

在这里插入图片描述

通过类或者对象都可以修改这个被 static 修饰的成员变量。

在这里插入图片描述

通过调试窗口也可以看到, classRoom 并没有被存到一个具体的对象中去。

static 修饰成员方法

public static void test(){
System.out.println("我来测试一下 static 修饰成员方法");
}

test();
Student stu1 = new Student("张三","123",18);
stu1.test();

在这里插入图片描述

需要注意的是:

  • 不能在静态方法中访问任何非静态成员变量

在这里插入图片描述

  • 静态方法中不能调用任何非静态方法

在这里插入图片描述

  • 静态方法中调用时候无法传递this引用

在这里插入图片描述

static 修饰的成员变量的初始化

分为就地初始化和静态代码块初始化。

就地初始化就是上文中在定义的时候直接给一个值。

代码块

使用{}定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:

  • 普通代码块

  • 构造块

  • 静态块

  • 同步代码块(将在多线程部分介绍)

普通代码块

直接定义在方法中的代码块

public void barkTest(){
// 测试普通代码块
{
int x = 10;
System.out.println(x);
}
System.out.println(this.name + "在Dog类测试普通代码块");
}

Dog dog = new Dog(1,"旺财");
dog.barkTest();

在这里插入图片描述

一般很少会用到这种写法

构造代码块

构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。

package Demo;

public class Dog {
// 不写访问修饰限定符,默认就为 default 的操作权限

int age;
String name;
{
this.age = 1;
this.name = "默认名称";
System.out.println("已执行构造代码块!");
}

public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.name);
System.out.println(dog.age);
}

public Dog() {

}

public Dog(int age, String name) {
this.age = age;
this.name = name;
}

public void barkTest(){
// 测试普通代码块
{
int x = 10;
System.out.println(x);
}
System.out.println(this.name + "在Dog类测试普通代码块");
}

public void bark(){
System.out.println(this.name + "正在汪汪叫");
}
}

在这里插入图片描述

静态代码块

package Demo;

public class Dog {
// 不写访问修饰限定符,默认就为 default 的操作权限
int age;

String name;

static String habit;

static {
habit = "出去玩";
System.out.println("执行了静态代码块");
}

{
this.age = 1;
this.name = "默认名称";
System.out.println("已执行构造代码块!");
}

public static void main(String[] args) {
Dog dog = new Dog();
System.out.println(dog.name);
System.out.println(dog.age);
System.out.println(dog.habit);
}

public Dog() {
}

public Dog(int age, String name) {
this.age = age;
this.name = name;
}

public void barkTest(){
// 测试普通代码块
{
int x = 10;
System.out.println(x);
}
System.out.println(this.name + "在Dog类测试普通代码块");
}

public void bark(){
System.out.println(this.name + "正在汪汪叫");
}
}

在这里插入图片描述


package Demo;

public class Dog {
// 不写访问修饰限定符,默认就为 default 的操作权限
int age;

String name;

static String habit;

static {
habit = "出去玩";
System.out.println("执行了静态代码块");
}

{
this.age = 1;
this.name = "默认名称";
System.out.println("已执行构造代码块!");
}

public static void main(String[] args) {
Dog dog = new Dog();
Systemout.println(dog.name);
System.out.println(dog.age);
System.out.println(dog.habit);
}

public Dog() {
System.out.println("执行了无参构造方法");
}

public Dog(int age, String name) {
this.age = age;
this.name = name;
}

public void barkTest(){
// 测试普通代码块
{
int x = 10;
System.out.println(x);
}
System.out.println(this.name + "在Dog类测试普通代码块");
}

public void bark(){
System.out.println(this.name + "正在汪汪叫");
}
}

在这里插入图片描述

可以看到,静态代码块是最先执行的,构造代码块其次,最后才是构造方法执行实例化对象。这说明静态代码块是随类加载进行加载。如果都是静态代码块那就根据书写的先后顺序进行加载。

对象的打印

这里及以后均是在继承与多态完成后回来进行更新

此时有一个 Dog 类

package Demo1;

public class Dog {
String name;
int age;
String habit;

public Dog(String name, int age, String habit) {
this.name = name;
this.age = age;
this.habit = habit;
}

public Dog(){

}
}

Dog dog = new Dog("大黄",1,"出去玩");
System.out.println(dog);

在这里插入图片描述

要想完整的打印对象需要重写 toString 方法

package Demo1;

public class Dog {
String name;
int age;
String habit;

public Dog(String name, int age, String habit) {
this.name = name;
this.age = age;
this.habit = habit;
}

public Dog(){

}

@Override
public String toString() {
return "Dog{" +
"name='" + name + '\\'' +
", age=" + age +
", habit='" + habit + '\\'' +
'}';
}
}

Dog dog = new Dog("大黄",1,"出去玩");
System.out.println(dog);

在这里插入图片描述

内部类

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部, 前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

根据内部类定义的位置不同,一般可以分为以下几种形式:

  • 成员内部类

  • 局部内部类

成员内部类


实例内部类

未被 static 修饰的内部类

package Demo1;

public class Out1 {
// 测试实例内部类

int a = 1;
protected int b = 2;
private int c = 3;
public int d = 4;

public void testMethod1(){
System.out.println("哈哈");
}

private void testMethod2(){
System.out.println("呵呵");
}

class Inner1{
int e = 5;

void inner1Test1(){
// 内部类的实例对象可以直接访问外部类中任意修饰符修饰的成员
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
testMethod1();
testMethod2();
}

}
}

内部类不能直接实例化

Inner1 inner1 = new Inner1();

在这里插入图片描述

实例内部类必须通过外部类的对象进行实例化

Out1 out1 = new Out1();
Out1.Inner1 inner1 = out1.new Inner1();

Out1.Inner1 要通过外部类 Out1 才能拿到这个内部类 Inner1 , 在实例化 Inner1 的对象时需要通过 Out1 这个类的对象进行实例化来进行实例化。

Out1 out1 = new Out1();
Out1.Inner1 inner1 = out1.new Inner1();
inner1.inner1Test1();

在这里插入图片描述

如果内部类和外部类存在同名成员,内部类在使用同名对象时会优先使用自己的同名成员。如果要使用外部类的成员,则需通过外部类对象.同名成员名或外部类名.this.同名成员名来使用。

package Demo1;

public class Out1 {
// 测试实例内部类

int a = 1;
protected int b = 2;
private int c = 3;
public int d = 4;
int e = 6;

public void testMethod1(){
System.out.println("哈哈");
}

private void testMethod2(){
System.out.println("呵呵");
}

class Inner1{
int e = 5;

void inner1Test1(){
// 内部类的实例对象可以直接访问外部类中任意修饰符修饰的成员
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
testMethod1();
testMethod2();
}

void innerTest2(){
// 在外部类和内部类存在同名成员时
// 优先使用内部类成员
Out1 out1 = new Out1();
System.out.println(e);
// 需要通过外部类对象访问外部类同名成员
System.out.println(out1.e);
// 或通过外部类.this.访同名成员名访问
System.out.println(Out1.this.e);
}

}
}

Out1 out1 = new Out1();
Out1.Inner1 inner1 = out1.new Inner1();
inner1.innerTest2();

在这里插入图片描述

而外部类对象访问内部类的成员,必须要通过內部类的实例化对象来进行访问

package Demo1;

public class Out1 {
// 测试实例内部类

int a = 1;
protected int b = 2;
private int c = 3;
public int d = 4;
int e = 6;

public void testMethod1(){
System.out.println("哈哈");
}

private void testMethod2(){
System.out.println("呵呵");
}

public void testMethod3(){
// 外部类对象像访问内部类的成员
// 必须要通过內部类的实例化对象来进行访问
Out1 out1 = new Out1();
Out1.Inner1 inner1 = out1.new Inner1();
System.out.println(inner1.num1);
System.out.println(inner1.num2);
System.out.println(inner1.e);

}

class Inner1{
int e = 5;
int num1 = 10;
int num2 = 20;
void inner1Test1(){
// 内部类的实例对象可以直接访问外部类中任意修饰符修饰的成员
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
testMethod1();
testMethod2();
}

void innerTest2(){
// 在外部类和内部类存在同名成员时
// 优先使用内部类成员
Out1 out1 = new Out1();
System.out.println(e);
// 需要通过外部类对象访问外部类同名成员
System.out.println(out1.e);
// 或通过外部类.this.访同名成员名访问
System.out.println(Out1.this.e);
}
}
}

Out1 out1 = new Out1();
out1.testMethod3();

在这里插入图片描述


静态内部类

被 static 修饰的内部类被称为静态内部类

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;

static class Inner2{
int c = 30;

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

静态内部类的实例化不需要通过外部类的对象进行

Out2.Inner2 inner2 = new Out2.Inner2();


静态内部类不能直接访问外部类的非静态成员

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;
static int d = 40;
static class Inner2{
int c = 30;

void inner2Test3(){
System.out.println(d);
}

void inner2Test2(){
// 静态内部类不能直接访问外部类的非静态成员
System.out.println(a);
System.out.println(b);
}

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

在这里插入图片描述


静态内部类可以直接访问外部类的静态成员

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;
static int d = 40;
static class Inner2{
int c = 30;

void inner2Test3(){
System.out.println(d);
}

// void inner2Test2(){
//// 静态内部类不能直接访问外部类的非静态成员
// System.out.println(a);
// System.out.println(b);
// }

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

Out2.Inner2 inner2 = new Out2.Inner2();
inner2.inner2Test3();

在这里插入图片描述


在静态内部类中访问外部类的非静态成员需要通过外部类的对象进行

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;
static int d = 40;
static class Inner2{
int c = 30;

void inner2Test4(){
// 在静态内部类中访问外部类的非静态成员需要通过外部类的对象进行
Out2 out2 = new Out2();
System.out.println(out2.a);
System.out.println(out2.b);
}

void inner2Test3(){
System.out.println(d);
}

// void inner2Test2(){
//// 静态内部类不能直接访问外部类的非静态成员
// System.out.println(a);
// System.out.println(b);
// }

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

Out2.Inner2 inner2 = new Out2.Inner2();
inner2.inner2Test4();

在这里插入图片描述


当静态内部类与外部类存在同名成员时,静态内部类会优先使用自己的成员,要访问外部类的成员变量需要通过外部类对象进行

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;
int c = 100;
static int d = 40;
static class Inner2{
int c = 30;

void inner2Test5(){
Out2 out2 = new Out2();
System.out.println(c);
System.out.println(out2.c);
}

void inner2Test4(){
// 在内部类中访问外部类的成员需要通过外部类的对象进行
Out2 out2 = new Out2();
System.out.println(out2.a);
System.out.println(out2.b);
}

void inner2Test3(){
System.out.println(d);
}

// void inner2Test2(){
//// 静态内部类不能直接访问外部类的非静态成员
// System.out.println(a);
// System.out.println(b);
// }

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

Out2.Inner2 inner2 = new Out2.Inner2();
inner2.inner2Test5();

在这里插入图片描述


外部类想要访问静态内部类的成员,要通过静态内部类的对象进行

package Demo2;

public class Out2 {

int a = 10;
protected int b = 20;
int c = 100;
static int d = 40;

void out2Test1(){
// 外部类想要访问静态内部类的成员,要通过静态内部类的对象进行
Inner2 inner2 = new Inner2();
System.out.println(inner2.num1);
System.out.println(inner2.num2);
}

static class Inner2{
int c = 30;
int num1 = 1;
int num2 = 2;
void inner2Test5(){
// 当静态内部类与外部类存在同名成员时
// 静态内部类会优先使用自己的成员
// 要访问外部类的成员变量需要通过外部类对象进行
Out2 out2 = new Out2();
System.out.println(c);
System.out.println(out2.c);
}

void inner2Test4(){
// 在内部类中访问外部类的成员需要通过外部类的对象进行
Out2 out2 = new Out2();
System.out.println(out2.a);
System.out.println(out2.b);
}

void inner2Test3(){
System.out.println(d);
}

// void inner2Test2(){
//// 静态内部类不能直接访问外部类的非静态成员
// System.out.println(a);
// System.out.println(b);
// }

void inner2Test1(){
System.out.println("这是静态内部类Inner2的inner2Test1方法");
}
}
}

Out2 out2 = new Out2();
out2.out2Test1();

在这里插入图片描述


局部内部类

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般使用的非常少

public void func(){
class Inner{
int data1 = 1;

}
Inner inner = new Inner();
System.out.println(inner.data1);
}


匿名内部类

此时有一个 Out3 类

package Demo3;

public class Out3 {

public void out3Test1(){
System.out.println("这是Out3类中的out3Test1方法");
}
}

new Out3(){
@Override
public void out3Test1() {
super.out3Test1();
}
};

这就是匿名内部类的写法。

Out3 out3 = new Out3(){
// 这就是匿名内部类的写法
@Override
public void out3Test1() {
System.out.println("这是重写后的out3Test1方法");
}
};
out3.out3Test1();

在这里插入图片描述

赞(0)
未经允许不得转载:171主机测评 » Java类与对象
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址