【Java SE】类与对象的认识

1.对于类与对象的认识

我们之前学习c语言就是在面向过程。面向过程注重过程是如何实现的。

以洗衣服为例,面向过程的解决思路如下:

把衣服浸湿
倒入洗衣液
搓衣服
换水
拧干
晾衣服

面向过程维护或者扩展起来会比较麻烦

Java是一门面向对象的语言,注重对象间的协作与交互而不需要关注具体细节如何实现。

依旧以洗衣服为例,面向对象的解决思路如下:

衣服
洗衣液
洗衣机

此时我们就只需要关注人,衣服,洗衣液,洗衣机之间的关系,不需要关注洗衣机内部如何工作。

2.类的定义及使用

2.1类与对象的初步认识

是对对象的特性的描述,对象的具体实例。
以洗衣机为例,所有洗衣机都有品牌,功率,型号,容量,工作方式等特性。依据这些特性我们才能生产出符合要求的洗衣机。

2.2类的定义格式

定义类需要使用 class 关键字。

class text {
field; //字段/属性/成员变量
method; //方法
}
  • class 紧随其后的是类名。{ }内部是类的主体。
  • 类包含的内容称为类的成员。
  • 属性是用来描述类的,称为类的成员属性或类成员变量。
  • 方法用于说明类的功能,称为类的成员方法。

这样我们就可以创建一个洗衣机类:

class WashingMachine{
    public String brand;//品牌
    public String type;//型号
    public double capacity;//容量
    public double power;//功率

    public void washClothes(){
        System.out.println("洗衣功能");
    }
    public void dryClothes(){
        System.out.println("脱水功能");
    }
}

注意: 类名命名为大驼峰,方法命名为小驼峰。

3.类的实例化

3.1什么是实例化?

定义一个类后相当于在计算机中创建了一个类型,类似于int , double
用类创建对象的过程就成为类的实例化
Java中使用 new 关键字来实例化对象。

public static void main1(String[] args) {    
   WashingMachine w1 = new WashingMachine(); 
   w1.washClothes(); 
   w1.dryClothes();
 }

注意:

  • 类后紧跟对象的命名。
  • 使用 . 来访问对象的属性或方法。

运行结果:
在这里插入图片描述

3.2 类和对象的说明

  • 类相当于模型,用于对一个实体进行描述,限定了成员。
  • 类是一种自定义类型,可以定义定义变量。
  • 一个类可以实例化多个对象,实例化出的对象占用实际的物理空间,储存类成员变量。
  • 做一个比方,类相当于建筑图纸,并没有占用实际空间。而实例化对象相当于照着图纸建造房子,此时可以储存数据。

4.this引用

4.1 为什么要用this引用?

举个例子:构造函数形参与成员变量不同命名时,我们可以很好的区分

class Date {
    public int year;
    public int month;
    public int day;
    public void setDay(int y, int m, int d){
        year = y;
        month = m;
        day = d;
    }
    public void printDate(Date this){
        System.out.println(this.year + "/" + this.month + "/" + this.day);
    }
}
public class C0507 {
    public static void main(String[] args) {
        // 构造三个日期类型的对象 d1 d2 d3
        Date d1 = new Date();
        Date d2 = new Date();
        Date d3 = new Date();
        // 对d1,d2,d3的日期设置
        d1.setDay(2020, 9, 15);
        d2.setDay(2020, 9, 16);
        d3.setDay(2020, 9, 17);
        // 打印日期中的内容
        d1.printDate();
        d2.printDate();
        d3.printDate();
    }

但如果当形参名与成员变量名相同,我们就需要思考:

  1. 究竟是谁赋值给谁?是成员变量给成员变量?还是参数给参数?
 public void setDay(int year, int month, int day){
        year = year;
        month = month;
        day = day;
    }
  1. 三个对象都调用了setDay()和printDate()函数,但是这两个函数没有任何有关对象的说明,那么setDay()是如何知道应该设置哪个对象的信息,printDate()是如何知道应该打印哪个对象的信息??

事实上,编译器不会报错,这是的变量默认为最近小括号内部的变量,这里也就是形参。这相当于自己给自己赋值,是无效的
在这里插入图片描述

为了方便区分局部变量和成员变量,用 this.变量 来指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有的成员变量的操作都可以通过this引用去访问。

 public void setDay(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }

4.2 this引用的特性

  1. this的类型:对应类类型引用,即哪个对象调用就是哪个对象的引用类型。
  2. this只能在成员方法中使用。
  3. 在成员方法中,this只能引用当前对象,不可以指向其他对象
  4. this是成员方法的第一个隐藏参数,编译器会自动传递,不需要手动编写。当成员方法执行时,编译器会负责将调用成员方法对象的引用传递给成员方法,this负责接收。
    在这里插入图片描述

5.对象的构造及初始化

Java中未初始化的局部变量不能使用。
在这里插入图片描述

这时只需要在创建变量时初始化就可以直接使用。
类中的字段也可以初始化。

5.1构造方法

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

注意:

  • 名字必须与类名相同,没有返回值,也不可以写void
  • 创建对象由对象自动调用,并且在对象的生命周期只调用一次(相当于人出生,每个人只能出生一次)
  • 构造函数的作用是对对象中的成员进行初始化,并不负责为对象开辟空间
  • 构造方法可以重载(可以根据需求输入不同参数来调用不同的构造方法)
public class Date {
  public int year;
  public int month;
  public int day;
  
  // 无参构造方法
  public Date(){
  this.year = 1900;
  this.month = 1;
  this.day = 1;
}

// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
Date d = new Date();
d.printDate();
}
}

上述两个构造方法名字相同,参数列表不同,因此构成了方法的重载。
注意:

  • 如果没有显式定义,编译器会自动生成默认的无参的构造方法。
  • 一旦用户定义,编译器就不会自动生成。
  • 可以用this 调用其他构造方法来简化代码,this必须在第一条语句
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法--内部给各个成员赋值初始值,该部分功能与三个参数的构造方法重复
// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法
// 但是this(1900,1,1);必须是构造方法中第一条语句
public Date(){
//System.out.println(year); 注释取消掉,编译会失败
this(1900, 1, 1);
  //this.year = 1900;
  //this.month = 1;
  //this.day = 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
}
  • this调用不可以构成环
public Date(){
this(1900,1,1);
}
public Date(int year, int month, int day) {
this();
}//编译报错:Error:(19, 12) java: 递归构造器调用

5.2默认初始化

在新建一个对象后,JVM层面会进行以下工作:

  1. 检测对象的对应类是否加载,如果没有加载则加载
  2. 为对象分配空间
  3. 处理并发安全问题
  4. 初始化所分配的空间
    即:对象空间申请好以后,对象中包含的成员就设置好了初始值
数据类型默认值
byte0
char‘\u0000’
short0
int0
long0
booleanfalse
double0.0
referencenull
  1. 设置对象头信息
  2. 调用构造方法,为各位各位成员赋值

6.封装

6.1封装的概念

面向对象的三大特性:封装,继承,多态 封装简单来说,就是包装起来,屏蔽细节。

例如:一部手机留给用户的只有充电口,听筒,扬声器等等,内部结构被手机壳封装起来。而手机真正工作时起作用的是内部组件

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

6.2访问限定符

访问权限用来控制方法或字段能否在类外使用

范围privatedefaultprotectpublic
同一包中同一类
同一包中不同类
不同包中的子类
不同包中的非子类

default 是指什么都不写的默认情况。

6.3 包

为了更好的管理类,把多个类组织在一起,成为软件包。有点类似于目录,包的本质就是文件夹。在同一工程中,允许有相同的类名,只要在不同的包中即可。

6.3.1 导入包

Java中已经提供了很多现成的类来给我们使用,例如Date类可以使用java.util.Date导入java.utill这个包中的Date类。

使用 import 语句可以导入包。

import java.util.Date;

如果需要导入包中的其他类,也可以用*

import java.util.*

6.3.2 自定义包

在文件最上方就加上package语句指定该文件在哪个包中

新建: src -> 新建 -> 软件包
在这里插入图片描述

常见的包:

  • java.lang :系统基础类(String,Object)
  • java.net:进行网络编程开发包
  • java.sql:进行数据开发的支持包
  • java.util:工具程序包(集合类)
  • Java.io:I/O编程开发包

7.static

在Java中被static修饰的成员,称之为静态成员,也称为类成员,不属于某个具体的对象,而是所有对象共享的。

7.1 static修饰成员变量

特性:

  1. 不属于某个对象,而是类的属性,是所有对象共享的,不存在某个对象的空间中。
  2. 既可以通过对象来访问,也可以通过类名来访问,但一般更推荐通过类名访问。
  3. 类变量存储在方法区
  4. 生命周期伴随类的一生。

7.2 static修饰成员方法

Java中被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象特有的。静态成员一般通过静态方法来访问。

特性:

  1. 不属于某个对象,是类方法
  2. 可以通过对象调用,也可以通过类.静态方法调用。更推荐后者
  3. 不能在静态方法中直接调用非静态成员变量,可以先创建对象,通过对象引用访问

static修饰的方法中不能有this,这两个关键字在逻辑上是冲突的,前者是属于类的,不属依赖对象,后者是某个具体的对象

8.代码块

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

  • 普通代码块: 定义在方法中的代码块,可以限定局部变量的生命周期和作用域,不经常使用
  • 构造代码块/实例代码快: 定义在类中的代码块,不加任何修饰符 。 构造代码块一般用于初始化实例成员变量
  • 静态代码块: 使用static定义的代码块称为静态代码块,一般用于初始化静态成员变量

执行顺序:

静态代码块
实例代码块
构造方法

这三类代码块的执行顺序与定义顺序无关,同种类型根据定义顺序依次执行

示例:

public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom;

//实例代码块
{
  this.name = "daisy";
  this.age = 12;
  this.gender = "man";
  System.out.println("实例代码执行");
}

// 静态代码块
static {
  classRoom = "202";
  System.out.println("静态代码执行");
}

// 构造方法
 public Student(){
  System.out.println("构造方法执行");
 }
 public static void main(String[] args) {
   Student s1 = new Student();
   Student s2 = new Student();
 }
}

运行结果:在这里插入图片描述

注意:

  • 静态代码块不论生成了多少对象,都只执行一次
  • 静态成员变量是类的属性,因此是JVM加载类时开辟空间并初始化的
  • 如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后顺序依次执行(相当于合并)
  • 实例代码块只有在创建对象的时候执行

9.内部类

9.1 什么是内部类

内部类是指将一个类定义在另一个类(外部类)或方法内部的特殊类结构。它是Java封装特性的重要体现,能够让内部结构与外部类形成紧密关联,同时避免与其他类产生命名冲突,让代码组织更具逻辑性。

举个简单的语法示例,如下代码中InnerClass就是定义在OutClass中的内部类:

public class OutClass {
    // 内部类
    class InnerClass{
    }
}
// OutClass:外部类
// InnerClass:内部类

注意:

  • 独立字节码文件:内部类与外部类共用同一个Java源文件,但编译后会生成单独的字节码文件,命名格式通常为“外部类名$内部类名.class”。
  • 非嵌套类不算内部类:若两个类定义在同一个.java文件中,但不在彼此的类体内部,它们只是独立的类,并非内部类与外部类的关系。例如:
public class A{
}
class B{
}
// A和B是两个独立类,无内部类与外部类关系

9.2 内部类的分类

根据内部类定义的位置和修饰符不同,可分为成员内部类局部内部类匿名内部类。其中成员内部类又分为实例内部类和静态内部类,是日常开发中相对常用的类型。

1. 成员内部类

成员内部类定义在外部类的成员位置(与外部类的属性、方法同级),根据是否被static修饰,又可细分为实例内部类和静态内部类。

(1) 实例内部类(未被static修饰)

实例内部类依赖于外部类对象存在,只有创建了外部类对象,才能创建实例内部类对象。它可以直接访问外部类的任意成员(包括private修饰的成员),但当与外部类存在同名成员时,需要通过特定语法区分。

代码示例

public class OutClass {
    private int a; // 外部类私有成员
    static int b;  // 外部类静态成员
    int c;         // 外部类普通成员

    // 外部类普通方法
    public void methodA(){
        a = 10;
        System.out.println(a);
    }

    // 外部类静态方法
    public static void methodB(){
        System.out.println(b);
    }

    // 实例内部类
    class InnerClass{
        int c; // 与外部类同名成员

        public void methodInner(){
            // 1. 直接访问外部类任意成员
            a = 100;       // 访问外部类私有成员
            b = 200;       // 访问外部类静态成员
            methodA();     // 调用外部类普通方法
            methodB();     // 调用外部类静态方法

            // 2. 访问同名成员:优先访问内部类自身成员
            c = 300;
            System.out.println(c); // 输出:300

            // 3. 访问外部类同名成员:外部类名.this.成员名
            OutClass.this.c = 400;
            System.out.println(OutClass.this.c); // 输出:400
        }
    }

    public static void main(String[] args) {
        // 创建外部类对象
        OutClass outClass = new OutClass();

        // 方式1:直接通过外部类对象创建实例内部类对象
        OutClass.InnerClass inner1 = outClass.new InnerClass();
        // 方式2:简化语法(不推荐,可读性较差)
        OutClass.InnerClass inner2 = new OutClass().new InnerClass();

        // 调用实例内部类方法
        inner2.methodInner();
    }
}

核心特性

  1. 访问权限:可直接访问外部类任意访问限定符(privatedefaultprotectedpublic)修饰的成员。
  2. 同名成员处理:当内部类与外部类成员同名时,优先访问内部类自身成员;若需访问外部类同名成员,需使用外部类名.this.成员名语法。
  3. 对象创建依赖:必须先创建外部类对象,才能通过外部类对象.new 内部类名()的方式创建实例内部类对象。
  4. 外部类访问内部类:外部类不能直接访问实例内部类成员,需先创建实例内部类对象才能访问。
(2) 静态内部类(被static修饰)

静态内部类不依赖于外部类对象,属于外部类本身,可直接通过外部类名访问。它的核心限制是:只能访问外部类的静态成员(静态属性、静态方法),无法访问外部类的非静态成员。

代码示例

public class OutClass {
    public int a = 1;
    public int b = 2;
    public static int c = 3;

    //静态内部类
    static class InnerClass{
        public int d = 4;
        public static int e = 5;

        public void test() {
            System.out.println("静态内部类成员方法");
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OutClass.InnerClass inner = new OutClass.InnerClass();
    }
}

OutClass.InnerClass 作为一个整体的类型

核心特性

  1. 成员访问限制:仅能访问外部类的静态成员,若需访问外部类非静态成员,需先创建外部类对象。
  2. 对象创建独立:无需依赖外部类对象,直接通过外部类名.内部类名()的方式创建对象。
  3. 访问权限控制:与实例内部类相同,受publicprivate等访问限定符约束(若被private修饰,仅外部类可访问)。

2.匿名内部类

匿名内部类是一种没有显式名称的内部类,它通常用于创建只需要使用一次的类实例。匿名内部类可以简化代码,尤其是在需要临时创建接口实现类或子类的场景中非常有用。

interface IA{
    void test01();
}

public class Test {
    IA a = new IA() {
        @Override
        public void test01() {
            System.out.println("test");
        }
    };
}

这里可以理解为a实现了接口IA并重写了test01方法

3. 局部内部类

局部内部类定义在外部类的方法体或代码块({})内部,作用域仅限于定义它的方法或代码块,日常开发中使用极少,仅需了解基本语法和特性即可。

代码示例

public class OutClass {
    int a = 10; // 外部类成员

    public void method(){
        int b = 10; // 方法局部变量

        // 局部内部类:定义在方法体内部
        class InnerClass{
            public void methodInner(){
                // 可访问外部类成员和方法局部变量
                System.out.println(a); // 输出:10
                System.out.println(b); // 输出:10
            }
        }

        // 仅能在当前方法体内创建并使用局部内部类对象
        InnerClass inner = new InnerClass();
        inner.methodInner();
    }

    public static void main(String[] args) {
        OutClass out = new OutClass();
        out.method();

        // 错误:无法在方法体外访问局部内部类
        // OutClass.InnerClass inner = null;
    }
}

核心特性

  1. 作用域局限:仅能在定义它的方法或代码块内部使用,外部无法访问。
  2. 无访问修饰符:不能被publicstaticprivate等修饰符修饰。
  3. 字节码命名:编译后生成的字节码文件命名格式为“外部类名$数字内部类名.class”(如OutClass$1InnerClass.class)。

9.3 内部类的应用场景

虽然内部类在日常开发中使用频率不如普通类,但在特定场景下能显著提升代码优雅性和封装性:

  1. 实现隐藏逻辑:当某个类仅为外部类服务(如辅助外部类实现特定功能),使用内部类可避免对外暴露该类,减少代码耦合。例如:ArrayList中的迭代器类Itr就是内部类,仅为ArrayList提供遍历功能。
  2. 解决多重继承问题:Java不支持类的多重继承,但可通过内部类间接实现——外部类和内部类可分别继承不同的类,从而让外部类间接拥有多个类的特性。
  3. 简化代码结构:在编写事件监听、线程匿名任务等场景时,匿名内部类(后续讲解)可减少类的定义数量,让代码更紧凑。

总结

  • 实例内部类:依赖外部类对象,可访问外部类任意成员,需通过外部类对象创建。
  • 静态内部类:不依赖外部类对象,仅能访问外部类静态成员,可直接通过外部类名创建。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值