欢迎光临
我们一直在努力

java基础知识--类和对象

什么是面向对象呢?

好比你正在用的抖音,开发者关注的是背后的逻辑代码,如何执行,如何给用户体验,如何加入数据,等等等。叫做面向过程

你作为一个用户在使用抖音时候只用关心如何使用软件就行,简化了过程,这就叫面向对象。

什么是类?
 

2. 类是干嘛的?

类只干一件事:定义一类事物拥有什么特征、能做什么。

  • 特征:name(名字)、age(年龄)、color(颜色)
  • 行为:eat()(吃饭)

类本身不是真实的狗,它只是狗的模板。


3. 对象是什么?

根据类模板造出来的具体东西,就叫对象(实例)。

java

运行

Dog dog = new Dog(); // 造了一只狗
Dog dog3 = new Dog("哈哈"); // 又造了一只狗

  • 类 = 狗的模板
  • 对象 = 模板造出来的一只只真实的狗

4. 最通俗的比喻

  • 类 = 月饼模具
  • 对象 = 用模具压出来的一个个月饼

模具(类)决定了月饼长什么样、有什么馅; 真实的月饼(对象)才是你能吃的东西。


5. 类的 3 个核心组成

  • 成员变量:事物的特征(名字、年龄、颜色)
  • 构造方法:创建对象的 “初始化器”
  • 成员方法:事物的行为(吃饭、跑、叫)
  • 类 = 模板 / 图纸,描述一类事物的特征和行为
  • 对象 = 根据模板造出来的具体实例
  • 先有类,才能造对象
  • class 类名{ … } 就是定义一个类
  • class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

    如何定义一个类?

    修饰符 class 类名 {
    // 1. 成员变量(特征)
    // 2. 构造方法(创建对象用)
    // 3. 成员方法(行为)
    }

    类的成员变量可以赋值也可以不赋值。

    class Dog {
    String name;
    int age;
    String color;

    class Dog {
    // 1. 成员变量(特征)
    String name;
    int age;
    String color = "黄色";

    赋值之后就变成默认值,不然不赋值要么默认值

  • 类名必须大驼峰 Dog、Person、Student(首字母大写)

  • 类里包含三样东西

    • 成员变量(特征)
    • 构造方法(创建对象)
    • 成员方法(行为)
  • 先定义类,再创建对象

  • Dog dog = new Dog("旺财");


    定义一个人类 Person

    class Person {
    String name;
    int age;

    public Person() { }

    public void sleep() {
    System.out.println(name + " 在睡觉");
    }
    }

    类中包含的内容称为类的成员。属性主要是⽤来描述类的,称之为类的成员属性或者类成员变量。⽅ 法主要说明类具有哪些功能,称为类的成员⽅法。

    那么方法怎么定义呢?

    方法分为有参数的方法和无参数的方法。
     

    . 无参方法:()里面空空啥也不写

    格式:返回值 方法名(){}

    java

    运行

    //无参:括号空
    public void eat(){
    System.out.println("小狗吃饭");
    }

    功能:固定逻辑,不需要外部给数据,吃饭内容写死

    2. 有参方法:()里必须写「数据类型 + 参数名」(形参)

    格式:返回值 方法名(类型 变量){}

    java

    运行

    //有参:括号内写类型+变量name
    public void eat(String dogName){
    System.out.println(dogName+"吃饭");
    }

    功能:需要外部传入数据,名字由调用时传入

    二、调用区分(使用方法时,最容易错在这里)

    1. 无参调用:括号必须空,不能填任何值

    java

    运行

    Dog d = new Dog();
    d.eat(); //正确:空括号
    //d.eat("旺财"); 错误!无参不能传数据

    2. 有参调用:括号必须传对应类型的数据(实参),个数、类型一一对应

    java

    运行

    d.eat("旺财");//正确:传入字符串
    //d.eat(); 错误!有参方法不能为空括号

    三、一句话通俗理解

    • 无参方法:自带全部数据,自己就能干活,不用你给东西 例:固定输出小狗吃饭
    • 有参方法:缺数据干不了活,调用必须你给它数据 例:不知道狗叫啥,需要你传入名字

    四、构造方法同理(你之前学的 Dog 构造)

    java

    运行

    public Dog(){}//无参构造 → new Dog();
    public Dog(String n){}//有参构造 → new Dog("旺财");

    五、避错 3 条铁律(杜绝乱调用)

  • 定义括号空 → 调用括号必空,不许传值
  • 定义括号有参数 → 调用必须传对应类型值,不能为空
  • 参数多个时:定义几个,调用就传几个,类型顺序一致 test(int a,String b)→test(10,"小黑")
  • 注意事项: 1. ⼀般⼀个⽂件当中只定义⼀个类 2. public修饰的类必须要和⽂件名相同 3. 不要轻易去修改public修饰的类的名称,如果要修改,通过开发⼯具修改、

    类的实现

  • 类 = 自定义数据类型(类似 int),只做模板,不能直接用
  • 实例化:new 类名(),用模板造出真实对象,格式:类名 对象名 = new 类名();
  • 访问成员:对象。属性 / 对象。方法 (),.访问变量和方法
  • 一个类可以 new 多个独立对象,各自属性互不干扰
  • 二、完整示例

    java

    运行

    //1.定义类(模板)
    class PetDog{
    String name;
    String color;
    //成员方法
    void barks(){
    System.out.println(name+":旺旺旺~~~");
    }
    void wag(){
    System.out.println(name+":摇尾巴~~~");
    }
    }

    public class Main {
    public static void main(String[] args) {
    //2.实例化:new创建对象
    PetDog dogh = new PetDog();
    PetDog dogs = new PetDog();

    //3.对象.变量 赋值
    dogh.name = "阿黄";
    dogh.color = "黑色";
    //对象.方法() 调用
    dogh.barks();
    dogh.wag();

    dogs.name = "赛虎";
    dogs.color = "黄色";
    dogs.barks();
    dogs.wag();
    }
    }

    三、运行结果

    plaintext

    阿黄:旺旺旺~~~
    阿黄:摇尾巴~~~
    赛虎:旺旺旺~~~
    赛虎:摇尾巴~~~

    四、口诀

    先写类做模板,new 实例造对象,小数点来访问,多个对象各存值。new关键字⽤于创建⼀个对象的实例. • 使⽤. 来访问对象中的属性和⽅法. • 同⼀个类可以创建多个实例. 3.3 类和对象的再次理解

    一、this 是什么?

    this = 当前对象自己 谁在调用方法 / 构造方法,this 就代表谁。

    你可以把 this 理解成:“我自己”


    二、this 最核心 3 个用法(必考、必用、必须会)

    1. this. 成员变量 → 区分 “局部变量” 和 “成员变量”

    最常见场景:构造方法里参数名和成员变量重名!

    java

    运行

    class Dog {
    // 成员变量
    String name;

    // 构造方法
    public Dog(String name) {
    // 等号左边:this.name = 成员变量
    // 等号右边:name = 传入的参数
    this.name = name;
    }
    }

    不加 this 会出错:

    java

    运行

    name = name; // 自己给自己赋值,成员变量没被赋值!

    加 this 才正确:

    java

    运行

    this.name = name; // 我的名字 = 你传进来的名字


    2. this () → 调用本类的其他构造方法

    作用:构造方法之间互相调用,减少重复代码

    java

    运行

    class Dog {
    String name;

    // 无参构造
    public Dog() {
    // 调用下面的有参构造
    this("无名小狗");
    }

    // 有参构造
    public Dog(String name) {
    this.name = name;
    }
    }

    规则:

    • this() 必须在构造方法第一行
    • 只能在构造方法里用
    • 不能自己调用自己(会死循环)

    3. this. 成员方法 → 调用本类的方法

    java

    运行

    public void eat() { … }

    public void play() {
    // 调用自己的eat方法
    this.eat();
    }

    平时可以省略,写 eat(); 就行。


    三、最清晰的一句话总结

    this 就是 “当前对象自己”

    • this.变量 → 用自己的成员变量
    • this() → 调用自己的其他构造
    • this.方法() → 调用自己的方法

    四、超级好记的例子(你一看就会)

    java

    运行

    class Dog {
    String name;

    // 构造1:无参
    public Dog() {
    // 调用构造2
    this("小狗");
    }

    // 构造2:有参
    public Dog(String name) {
    // 成员变量 = 参数
    this.name = name;
    }

    public void show() {
    // 调用自己的方法
    this.printName();
    }

    public void printName() {
    System.out.println("我叫:" + this.name);
    }
    }


    五、this 必背 3 条铁律

  • 谁调用方法,this 就代表谁
  • 变量重名必须用 this. 成员变量
  • this () 只能放在构造方法第一行

  • 最终总结

    一句话:

    this. 就是用来区分:哪个是对象自己的变量,哪个是参数!


    二、作用 2:调用本类的其他构造方法(代码复用)

    场景:

    一个类有多个构造方法(无参、有参),想让它们互相调用。

    java

    运行

    class Dog {
    String name;

    // 无参构造
    public Dog() {
    // 调用下面的有参构造
    this("无名小狗");
    }

    // 有参构造
    public Dog(String name) {
    this.name = name;
    }
    }

    规则(必须背):


    三、最终极简总结(构造方法里的 this)


    四、最容易记的比喻


    一句话终极记忆

    构造方法里: this. 赋值,this () 调用别的构造!

    需要我给你出1 道改错题,马上检验你是否真的懂了吗?

    ok

    1 道必懂改错题(专门考 this 在构造方法里的用法)

    题目

    下面代码有 2 个错误,运行后名字不会变成 “旺财”,请找出并改正!

    java

    运行

    class Dog {
    String name;

    // 构造方法
    public Dog(String name) {
    name = name; // 错误1
    }

    public Dog() {
    // 想调用有参构造,默认名字"小狗"
    this("小狗");
    System.out.println("无参构造"); // 错误2
    }
    }

    你的任务

    直接把你的答案发我,我马上给你批改 + 详细讲解!

    this.name=name;

    太棒了!第一个错误你完全答对了! 👏

    错误 1 修正(你答对了)

    错误原因: name = name; 只是把参数自己赋值给自己,对象的成员变量根本没收到值。

    正确写法:

    java

    运行

    public Dog(String name) {
    this.name = name; // ✅ 你写对了!
    }


    现在来看 错误 2(必考重点)

    java

    运行

    public Dog() {
    this("小狗"); // 调用构造
    System.out.println("无参构造"); // 这行代码放这里对吗?
    }

    问题: this(…) 调用其他构造方法时,必须放在构造方法的第一行!

    这里虽然逻辑没错,但我要考你的是顺序。 如果代码写成这样:

    java

    运行

    public Dog() {
    System.out.println("无参构造"); // 先写了别的代码
    this("小狗"); // 后写 this() —— ❌ 报错!
    }

    这才是真正的错误!


    最终终极结论(背下来,构造方法 this 永不丢分)


    最终正确完整代码

    java

    运行

    class Dog {
    String name;

    // 有参构造
    public Dog(String name) {
    this.name = name; // ✅ this. 赋值
    }

    // 无参构造
    public Dog() {
    this("小狗"); // ✅ this() 调用,必须第一行
    System.out.println("无参构造");
    }
    }

    • this = 当前对象自己
    • this. 变量 → 解决变量重名
    • this() → 调用本类构造
    • this. 方法 () → 调用本类方法
    • this 关键字在构造方法里的 2 个核心作用(超级直白解释)

      我只讲构造方法里的用法,专门帮你搞定你现在最晕的点!


      一、作用 1:给成员变量赋值(最常用、最重要)

      场景:

      构造方法的参数名字 和 类里的成员变量名字 一模一样!

      java

      运行

      class Dog {
      String name; // 成员变量

      // 构造方法
      public Dog(String name) { // 参数 name
      // 这里必须用 this!
      this.name = name;
      }
      }

      为什么要用 this?

    • name = name; → 错! 自己给自己赋值,成员变量根本没拿到值
    • this.name = name; → 对!
      • this.name = 我这个对象自己的名字(成员变量)
      • name = 你传进来的参数
    • this() 只能写在构造方法里面
    • 必须放在第一行!
    • 作用:少写重复代码
    • this.变量 → 给当前对象的成员变量赋值(解决名字重复)
    • this(…) → 调用本类的其他构造方法(简化代码)
    • this = 我自己(当前正在创建的对象)
    • this.name = 我的名字
    • this("旺财") = 调用我自己的另一个构造方法
    • 指出错误 1是什么?怎么改?
    • 指出错误 2是什么?怎么改?
    • 赋值用 this.变量

      java

      运行

      this.name = name;

    • 调用构造用 this(…)

      java

      运行

      this("参数");

    • this(…) 必须写在第一行!
    • 当自己给自己赋值时就会出现全部为0;没有给对象赋值

    当只调用d1的setday和printdate时

    当d1调用时this对setday进行标识为d1setday;

    参数的实列化;

    初始化

    当变量没有赋值的时候,根据类型的不同进行默认初始化。

    一、按变量位置分:成员变量 vs 局部变量

    这是最基础的分类,先分清变量写在哪:

  • 成员变量:写在类里面、方法外面
  • 局部变量:写在方法 / 代码块里面
  • 1. 成员变量初始化(3 种方式)

    成员变量属于对象 / 类,系统会自动赋默认值,也可以手动初始化。

    (1)默认初始化(系统自动执行,无需写代码)

    创建对象时,JVM 自动给成员变量赋默认值,不用手动赋值。

    • 基本类型:int=0、double=0.0、boolean=false、char=\\u0000
    • 引用类型:null(对象、数组、String 等)

    public class Student {
    // 成员变量,系统自动初始化
    int age; // 默认 0
    String name; // 默认 null
    boolean isMale; // 默认 false

    public static void main(String[] args) {
    Student s = new Student();
    System.out.println(s.age); // 输出 0
    System.out.println(s.name); // 输出 null
    }
    }

    (2)显式初始化(声明时直接赋值)

    定义变量时直接写值,优先级高于默认初始化。

    public class Student {
    // 显式初始化
    int age = 18;
    String name = "张三";

    public static void main(String[] args) {
    Student s = new Student();
    System.out.println(s.age); // 输出 18
    }
    }

    (3)构造器初始化(创建对象时赋值)

    用构造方法给成员变量赋值,灵活性最高,适合创建对象时动态传值。

    构造方法不能给返回类型!

    public class Student {
    int age;
    String name;

    // 构造器初始化
    public Student(int age, String name) {
    this.age = age;
    this.name = name;
    }

    public static void main(String[] args) {
    // 创建对象时赋值
    Student s = new Student(20, "李四");
    System.out.println(s.age); // 输出 20
    }
    }


    2. 局部变量初始化(强制手动赋值)

    局部变量属于方法 / 代码块,JVM 不会自动赋默认值,必须手动赋值后才能使用,否则编译报错!

    public class Test {
    public void method() {
    // 局部变量
    int num;
    // 错误!未赋值不能使用
    // System.out.println(num);

    num = 10; // 手动赋值
    System.out.println(num); // 正确,输出 10
    }
    }


    二、按静态 / 非静态分:静态初始化

    针对静态变量(static 修饰),属于类本身,和对象无关,加载类时就执行。

    1. 静态变量初始化(2 种方式)

    (1)静态显式初始化

    声明静态变量时直接赋值:

    public class Test {
    // 静态显式初始化
    static int count = 100;
    }

    (2)静态代码块初始化

    用 static{} 代码块,适合复杂逻辑初始化(比如赋值前计算、读取配置),类加载时执行 1 次。

    public class Test {
    static int num;

    // 静态代码块:类加载时执行,仅执行一次
    static {
    num = 200;
    System.out.println("静态代码块执行");
    }

    public static void main(String[] args) {
    System.out.println(num); // 输出 200
    }
    }


    三、补充:实例代码块初始化

    属于对象初始化,用 {} 写在类里、方法外,创建对象时自动执行,每次 new 对象都会跑一次。

    执行时机:早于构造器,晚于显式初始化。

    public class Test {
    int a = 10; // 显式初始化

    // 实例代码块
    {
    a = 20;
    System.out.println("实例代码块执行");
    }

    // 构造器
    public Test() {
    a = 30;
    }

    public static void main(String[] args) {
    Test t = new Test();
    System.out.println(t.a); // 输出 30
    }
    }


    四、Java 初始化执行顺序(必考!)

    把所有初始化方式放一起,固定执行顺序:

  • 静态变量默认值 → 静态显式初始化 / 静态代码块(类加载,仅 1 次)
  • 成员变量默认值 → 成员显式初始化 / 实例代码块
  • 构造器初始化
  • 口诀:先静态,后对象;先默认,后手动;先代码块,后构造器


    总结

  • 成员变量:默认初始化 → 显式初始化 → 实例代码块 → 构造器(自动赋默认值)
  • 局部变量:必须手动赋值,无默认值
  • 静态变量:静态显式初始化 / 静态代码块(类加载执行 1 次)
  • 执行顺序:静态优先 → 成员变量 → 构造器
  • 静态初始化>成员变量>构造器
  • 构造方法初始化

    一、什么是构造方法?

    构造方法 = 创建对象时自动调用的 “特殊方法” 作用:给对象初始化赋值(给成员变量设初值)。

    你可以把它理解成:

    new 对象的时候,第一个自动跑的方法


    二、构造方法的 5 个核心特点(必须背下来)

  • 方法名必须和类名完全一样(大小写都要一致)
  • 没有返回值类型(连 void 都不能写)
  • 创建对象时自动调用,不能手动调用
  • 每个类默认自带一个无参构造(你不写,Java 自动给)
  • 可以方法重载(一个类写多个构造方法)

  • 三、最简单示例

    java

    运行

    public class Student {
    // 成员变量
    String name;
    int age;

    // 构造方法:名字 = 类名,无返回值
    public Student() {
    name = "默认名字";
    age = 18;
    System.out.println("构造方法执行了!");
    }

    public static void main(String[] args) {
    // new 对象 → 自动调用构造方法
    Student s = new Student();
    System.out.println(s.name); // 输出:默认名字
    }
    }

    运行结果:

    plaintext

    构造方法执行了!
    默认名字


    四、带参数的构造方法(最常用!)

    用来创建对象时直接赋值,非常方便。

    java

    运行

    public class Student {
    String name;
    int age;

    // 带参构造
    public Student(String name, int age) {
    this.name = name; // this 代表当前对象
    this.age = age;
    }

    public static void main(String[] args) {
    // 创建对象时直接传值
    Student s1 = new Student("张三", 20);
    Student s2 = new Student("李四", 22);

    System.out.println(s1.name); // 张三
    System.out.println(s2.name); // 李四
    }
    }

    重点:this 是什么?

    this.变量名 = 当前对象的成员变量 用来区分成员变量和方法参数重名的情况。


    五、构造方法重载

    一个类可以有多个构造方法,参数不同就行。

    java

    运行

    public class Student {
    String name;
    int age;

    // 无参构造
    public Student() {}

    // 1参构造
    public Student(String name) {
    this.name = name;
    }

    // 2参构造
    public Student(String name, int age) {
    this.name = name;
    this.age = age;
    }
    }


    六、超级重要规则(面试 / 写代码必坑)

    规则 1:如果你写了带参构造

    Java 不会再给你自动生成无参构造!

    这会导致:

    java

    运行

    Student s = new Student(); // 报错!找不到无参构造

    解决办法

    手动写一个无参构造方法(企业开发规范)。


    七、构造方法执行顺序(和初始化一起考)

  • 静态代码块(只执行 1 次)
  • 成员变量默认初始化
  • 成员变量显式赋值
  • 构造方法执行

  • 八、一句话总结构造方法

    这就是: 无参构造 → 调用 → 三参构造 → 完成初始化


    代码原理一步步拆解

    看你给的代码:

    java

    运行

    public Date(){
    this(1900, 1, 1); // ① 这一行就是“跳转指令”
    }

    public Date(int year, int month, int day) { // ② 跳到这里执行
    this.year = year;
    this.month = month;
    this.day = day;
    }

    执行流程(超级重要)

    当你写:

    java

    运行

    Date d = new Date();

    真正发生的是:


    为什么必须写在第一行?

    Java 规定: 对象必须先完成核心初始化,才能执行你自己的代码。

    所以:

    比如:

    java

    运行

    Date() {
    this(1,2,3);
    }

    Date(int y,int m,int d) {
    this();
    }

    这就变成: 无参 → 三参 → 无参 → 三参 → 死循环! Java 直接编译报错,不让你这么写。


    最终极通俗总结

    this(…) 的原理就是:

    当前构造方法,委托另一个构造方法来完成对象初始化。

    作用:

  • 名字和类一样
  • 无返回值
  • new 对象时自动调用
  • 用来给对象赋初值
  • 可以重载,建议永远保留无参构造
  • 一、构造里 this (参数) 调用本类其他构造

    1. 作用:代码复用

    无参构造不想重复写赋值代码,直接调用三参构造。

    java

    运行

    public Date(){
    this(1900,1,1); // 调用下面三个参数的构造
    }

    new Date() → 走无参构造 → this(1900,1,1) 跳转执行 Date(int y,int m,int d),自动给年月日赋值 1900-1-1。

    两条硬性规矩

    构造方法里用 this(…) 调用别的构造,原理到底是什么?


    一句话核心原理

    你在一个构造方法里写 this(…),本质就是:让当前对象先去执行另一个构造方法,再回来继续执行自己。


    用生活例子秒懂

    你去餐厅吃饭:

  • 无参构造:你说 “来一份默认套餐”
  • 服务员不自己做,而是喊后厨做一份 1900-1-1 套餐
  • 后厨(三参构造)做好后
  • 再把餐给你
  • 进入无参构造
  • 看到第一行 this(1900,1,1)
  • 立刻跳转到三参构造
  • 三参构造给 year/month/day 赋值
  • 三参构造执行完毕
  • 回到无参构造(如果后面还有代码就继续执行)
  • 对象创建完成
  • this(…) 必须是构造方法第一条语句
  • 不能前面写输出、赋值、计算……
  • 少写重复代码
  • 统一赋值逻辑
  • 让代码更干净
  • 一、执行流程图(new Date () 全过程)

    plaintext

    new Date()

    开辟堆内存 → 成员变量默认初始化(year=0,month=0,day=0)

    进入【无参构造 Date()】

    第一行:this(1900,1,1) → 跳转【三参构造Date(int y,m,d)】

    三参内:this.year=1900;this.month=1;this.day=1(覆盖默认值)

    三参构造执行结束,回到无参构造剩余代码(无代码直接结束)

    对象创建完毕,地址赋给引用变量

    二、为什么必须第一行?

    对象要先完成属性初始化,才能执行构造里自定义代码。 如果:

    java

    运行

    public Date(){
    System.out.println("123");
    this(1900,1,1);
    }

    先执行输出再初始化,违背 Java 对象创建顺序 → 编译报错。

    三、循环调用报错原理图

    plaintext

    无参构造() → this(1,2,3)→三参构造

    三参构造→this()→无参构造

    无限递归闭环 → 编译器直接禁止

    四、核心原理一句话

    this(实参) = 本构造把初始化工作委托给同类另一个构造,共用一套赋值逻辑,消除重复代码。

    小练习

    java

    运行

    public Test(){
    this(5);
    System.out.println("A");
    }
    public Test(int a){
    System.out.println("B");
    }
    new Test();


    为什么不能循环调用?

  • this () 必须写在方法第一行,前面不能有任何代码。
  • java

    运行

    // 报错
    public Date(){
    System.out.println();
    this(1900,1,1);
    }

  • 不能互相循环调用(闭环)
  • java

    运行

    Date(){this(1900,1,1);}
    Date(int a,int b,int c){this();}

    无参调三参、三参又调无参,死循环,编译报错。

    修饰符补充

    构造一般 public,全项目随便 new; private 修饰构造:外面不能 new 对象,单例模式专用。

    二、打印对象:toString ()

    1. 不重写 toString,直接打印对象

    java

    运行

    Person p = new Person("Jim","男",18);
    System.out.println(p);

    输出:包名.Person@一串哈希码 原因:所有类默认继承 Object,自带原生 toString,只输出地址格式,不输出属性。

    2. 重写 toString:自定义打印内容

    java

    运行

    @Override
    public String toString() {
    return "[" + name + "," + gender + "," + age + "]";
    }

    System.out.println(对象)时,自动调用 toString 方法,打印你 return 的字符串。 输出:[Jim,男,18]

    一句话总结

  • 构造中this(实参):复用别的构造代码,首行、不能互调;
  • toString:重写后打印对象不再出地址,直接输出对象数据。
  • 一、封装到底是什么?

    一句话: 把类的成员变量(数据)私有化,不让外面随便改,只留公开的方法给外面访问和修改。

    就像:

    • 你的书包(类)
    • 里面的东西(成员变量)
    • 你不想别人随便乱翻、乱改
    • 只允许别人通过你允许的方式看 / 拿(get/set 方法)

    这就是 封装。


    二、为什么要用封装?

  • 保护数据,别人不能随便乱改
  • 代码更安全
  • 方便后期维护
  • 符合 Java 开发规范(企业开发必须用封装)

  • 三、封装的 3 个固定步骤(背会这 3 步就会了)

    步骤 1:给成员变量加 private(私有化)

    java

    运行

    private String name;
    private int age;

    加了 private → 只有自己类能访问,外面不能直接访问。

    步骤 2:提供公开的 get 方法(获取值)

    java

    运行

    public String getName() {
    return name;
    }

    public int getAge() {
    return age;
    }

    步骤 3:提供公开的 set 方法(设置值)

    java

    运行

    public void setName(String name) {
    this.name = name;
    }

    public void setAge(int age) {
    this.age = age;
    }


    四、完整封装示例(你能直接看懂)

    java

    运行

    public class Student {
    // 1. 私有化成员变量(封装核心)
    private String name;
    private int age;

    // 构造方法
    public Student(String name, int age) {
    this.name = name;
    this.age = age;
    }

    // 2. get 方法:获取值
    public String getName() {
    return name;
    }

    public int getAge() {
    return age;
    }

    // 3. set 方法:修改值
    public void setName(String name) {
    this.name = name;
    }

    public void setAge(int age) {
    // 封装最大好处:可以加判断!安全!
    if(age < 0 || age > 150) {
    System.out.println("年龄不合法!");
    return;
    }
    this.age = age;
    }
    }

    使用的时候:

    java

    运行

    public class Test {
    public static void main(String[] args) {
    Student s = new Student("张三", 18);

    // 不能直接 s.name 或 s.age(会报错)
    // 必须用 get/set

    System.out.println(s.getName());
    System.out.println(s.getAge());

    s.setName("李四");
    s.setAge(20);

    s.setAge(1000); // 不合法,会被拦截
    }
    }


    五、封装的最大好处:可以加校验规则

    没封装前:

    java

    运行

    s.age = 1000; // 能改,但不合理

    有封装后:

    java

    运行

    public void setAge(int age) {
    if(age < 0 || age > 150) {
    System.out.println("年龄错误!");
    return;
    }
    this.age = age;
    }

    数据变得安全、干净、合法!


    六、最简单总结(必背)

  • 封装 = 私有化 + get/set 方法
  • private → 只能本类访问
  • getXXX() → 获取值
  • setXXX() → 设置值(可加判断)
  • 封装目的:保护数据、提高安全性

  • 你之前的代码,改成封装版就是这样:

    java

    运行

    public class Student {
    // 私有化
    private String name;
    private int age;

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

    // get、set
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    }


    你现在完全懂封装了吗? 我可以再给你做一个不封装 vs 封装的对比,让你一眼看出差距!

    好的

    封装终极对比:不封装 vs 封装

    我用最直观的代码对比,让你一眼看懂封装到底有多重要!

    一、先看:不封装的代码(危险版)

    java

    运行

    public class Student {
    // 没有private,谁都能改!
    String name;
    int age;

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

    测试(随便乱改,完全失控)

    java

    运行

    public class Test {
    public static void main(String[] args) {
    Student s = new Student("张三", 18);

    // 想怎么改就怎么改,没有任何限制!
    s.age = -10; // 年龄负数,不合理
    s.age = 1000; // 年龄1000岁,荒唐
    s.name = ""; // 名字为空

    System.out.println(s.age); // 输出 1000
    }
    }

    问题:

    数据完全不安全,想改就改,程序会出大问题!


    二、再看:封装后的代码(安全版)

    java

    运行

    public class Student {
    // 1. 私有化(核心!)
    private String name;
    private int age;

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

    // 2. get方法:获取数据
    public String getName() {
    return name;
    }

    public int getAge() {
    return age;
    }

    // 3. set方法:设置数据(能加判断!)
    public void setAge(int age) {
    // 封装的超级好处:拦截非法数据!
    if(age < 0 || age > 150) {
    System.out.println("年龄不合法!设置失败");
    return;
    }
    this.age = age;
    }
    }

    测试(非法数据会被拦住)

    java

    运行

    public class Test {
    public static void main(String[] args) {
    Student s = new Student("张三", 18);

    // s.age = 1000; ❌ 报错!不能直接访问private变量

    s.setAge(1000); // 输出:年龄不合法!设置失败
    s.setAge(20); // 正常

    System.out.println(s.getAge()); // 输出 20
    }
    }


    三、一句话总结差距

    • 不封装:变量裸奔,谁都能改,数据不安全
    • 封装:变量私有化,只能通过get/set访问,可控制、可校验、更安全

    四、封装 3 句口诀(背会就精通)

    java

    运行

    //包1
    public class Person{
    protected int age;
    }
    //包2,子类继承Person
    public class Student extends Person{
    void test(){
    System.out.println(age);//跨包子类,protected可以访问
    }
    }
    //包2,无关类
    public class Test{
    void test(){
    Person p=new Person();
    p.age;//报错!不同包非子类不能访问protected
    }
    }

    4.public(公共)

    规则:全范围无障碍,任何包、任何类都能访问

    java

    运行

    //包A
    public class A{
    public String info="公共数据";
    }
    //任意包B
    class B{
    void fun(){
    A a=new A();
    System.out.println(a.info);//随便访问
    }
    }

    快速记忆口诀

    实际开发用法

    把你之前 Student 改成标准封装版

    java

    运行

    public class Student {
    //1.私有化成员变量
    private String name;
    private int age;
    private int food;

    //构造
    public Student(String name, int age) {
    this.name = name;
    //构造里也可以加校验
    if(age>0&&age<150){
    this.age = age;
    }else{
    this.age=0;
    System.out.println("年龄非法");
    }
    }

    //get取值
    public String getName() {
    return name;
    }
    public int getAge() {
    return age;
    }
    //set改值(封装关键:拦截非法数据)
    public void setAge(int age) {
    if(age<0||age>150){
    System.out.println("年龄设置失败!");
    return;
    }
    this.age = age;
    }

    public void eat(String food) {
    System.out.println(food+"马铃薯");
    }
    public void sleep() {
    System.out.println(name + "在睡觉,现在" + age + "岁还睡觉呢?");
    }

    public static void main(String[] args) {
    Student s = new Student("张三",18);
    //s.age=200; 报错,private不能直接访问
    s.setAge(200); //输出:年龄设置失败!
    s.setAge(20);
    System.out.println(s.getAge());//20
    s.sleep();
    }
    }

    需要我单独出一道封装练习题吗?

    好的

    封装课堂练习题(基础必做,跟着要求一步步写)

    题目需求

    创建 Person 类,完成标准封装:

    先自己写,写完对照参考答案

    参考答案

    java

    运行

    public class Person {
    //1.私有化成员变量
    private String name;
    private int age;
    private char gender;

    //无参构造
    public Person(){}
    //全参构造
    public Person(String name, int age, char gender) {
    this.name = name;
    //构造器内同样做校验
    setAge(age);
    setGender(gender);
    }

    //get/set name
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }

    //get/set age 带校验
    public int getAge() {
    return age;
    }
    public void setAge(int age) {
    if(age < 0 || age > 120){
    System.out.println("年龄不合法,赋值失败");
    return;
    }
    this.age = age;
    }

    //get/set gender 带校验
    public char getGender() {
    return gender;
    }
    public void setGender(char gender) {
    if(gender != '男' && gender != '女'){
    System.out.println("性别错误");
    return;
    }
    this.gender = gender;
    }

    //展示信息方法
    public void showInfo(){
    System.out.println("姓名:"+name+",年龄:"+age+",性别:"+gender);
    }

    public static void main(String[] args) {
    //1.全参构造创建对象
    Person p = new Person("小明",25,'男');
    p.showInfo();

    //2.修改年龄
    p.setAge(-5);
    p.setAge(200);
    p.setAge(30);

    //3.修改性别
    p.setGender('x');
    p.setGender('女');

    p.showInfo();
    }
    }

    运行结果

    plaintext

    姓名:小明,年龄:25,性别:男
    年龄不合法,赋值失败
    年龄不合法,赋值失败
    性别错误
    姓名:小明,年龄:30,性别:女

  • 变量私有化(加private)
  • 获取用 get(getName())
  • 修改用 set(setAge())

    Java 4 种访问修饰符完整详解(对照表格)

    表格

    权限同一个类同包不同类不同包子类不同包无关类
    private私有 ✅能访问 ❌不能 ❌不能 ❌不能
    default默认 (不写修饰符) ✅能访问 ✅能访问 ❌不能 ❌不能
    protected受保护 ✅能访问 ✅能访问 ✅能访问 ❌不能
    public公共 ✅能访问 ✅能访问 ✅能访问 ✅能访问

    1.private(私有)

    规则:只允许本类内部访问,出了这个类哪里都不能直接用

  • 场景:封装成员变量首选private,这就是之前封装把变量私有化的原因。
  • java

    运行

    class Student{
    private String name;
    //本类里可以正常用
    public void test(){
    System.out.println(name);
    }
    }
    //同包别的类
    class Test{
    public static void main(String[] args){
    Student s=new Student();
    s.name;//报错!private出类不能访问
    }
    }

    2.default(默认权限,不写任何关键字)

    规则:同一个包内所有类随便访问,跨包一律不行

    没有default关键字,变量 / 方法前面啥都不加就是默认权限

  • 范围:同包同类 ✅、同包异类✅;跨包不管是不是子类全❌
  • java

    运行

    //包A
    class Student{
    String name;//默认权限
    }
    //同包A的Test类
    class Test{
    void fun(){
    Student s=new Student();
    System.out.println(s.name);//正常访问
    }
    }
    //包B(跨包)
    class Demo{
    void fun(){
    Student s=new Student();
    s.name;//编译报错,跨包不能访问default
    }
    }

    3.protected(受保护)

    规则:

  • 本类、同包所有类 → ✅
  • 不同包的子类(继承 extends)→✅
  • 不同包毫无关系的类 →❌
  • 核心:跨包只有子类能访问,普通类不行
  • 类、成员变量、方法都能用 public,项目通用的方法 / 类用它。
  • private:足不出户(仅限本类)
  • default:邻里串门(仅限同包)
  • protected:亲戚能来(同包 + 跨包子类)
  • public:全世界通行(任意地方)
  • 成员变量一律 private(封装),靠 get/set 取值改值
  • 工具方法、对外使用的方法 public
  • 需要给子类继承使用、同包调用的方法用 protected
  • default 日常很少主动用

    包 1:com.one → Parent.java(父类,四种修饰变量)

    java

    运行

    package com.one;

    public class Parent {
    //四种访问权限成员变量
    private int pri = 10; //private私有
    int def = 20; //default默认(不写修饰符)
    protected int pro = 30; //protected受保护
    public int pub = 40; //public公共

    //本类内部:四种全能访问 ✅
    public void show() {
    System.out.println("本类访问:"+pri+" "+def+" "+pro+" "+pub);
    }
    }

    包 1:com.one → TestSame.java(同包无关类)

    java

    运行

    package com.one;

    //和Parent同一个包
    public class TestSame {
    public static void main(String[] args) {
    Parent p = new Parent();
    //同包:private❌,default✅ protected✅ public✅
    //System.out.println(p.pri); //报错,私有不能跨类
    System.out.println("同包普通类:"+p.def+" "+p.pro+" "+p.pub);
    }
    }

    运行结果:同包普通类:20 30 40

    包 2:com.two → Son.java(跨包、继承 Parent)

    java

    运行

    package com.two;
    import com.one.Parent;

    //跨包子类
    public class Son extends Parent{
    public void test(){
    //不同包子类:private❌ default❌ protected✅ public✅
    //System.out.println(pri); //报错
    //System.out.println(def); //报错,default跨包不行
    System.out.println("跨包子类:"+pro+" "+pub);
    }

    public static void main(String[] args) {
    Son s = new Son();
    s.test();
    }
    }

    运行结果:跨包子类:30 40

    包 2:com.two → TestOther.java(跨包、无关类,无继承)

    java

    运行

    package com.two;
    import com.one.Parent;

    //不同包毫无关系
    public class TestOther {
    public static void main(String[] args) {
    Parent p = new Parent();
    //跨包无关:只有public✅,剩下全❌
    //p.pri; p.def; p.pro; 全部编译报错
    System.out.println("跨包无关类:"+p.pub);
    }
    }

    运行结果:跨包无关类:40

    汇总表格(对照代码)

    表格

    修饰符同类同包不同类不同包子类不同包无关类
    private
    default (无关键字)
    protected
    public

    回到【封装】核心总结

  • 成员变量全部 private 私有化(外面不能直接。变量修改)
  • 对外提供 get/set 方法 (public),在 set 里加数据校验,控制赋值
  • 成员变量:private String name、private int age、private char gender(性别)
  • 生成:无参构造、全参构造
  • 每个变量写 get/set 方法:
    • setAge:年龄范围 0~120,超出提示「年龄不合法,赋值失败」,不修改值
    • setGender:性别只能是 '男' / '女',其他字符提示「性别错误」
  • 成员方法:showInfo(),打印:姓名:xx,年龄:xx,性别:xx
  • main 方法测试: ① 全参构造创建对象:姓名 = 小明,年龄 = 25,性别 = 男,调用 showInfo () ② 调用 setAge (-5)、setAge (200)、setAge (30),观察效果 ③ 调用 setGender ('x')、setGender (' 女 '),观察效果
  • static

    在Java中,被static修饰的成员,称之为静态成员,也可 以称为类成员,其不属于某个具体的对象,是所有对象所共享的。static修饰的成员变量,称为静态成员变量,静态成员变量最⼤的特性:不属于某个具体的对象,是所 有对象所共享的。

     1. 不属于某个具体对象,是所有对象共享的

    口头一点就是说黑板是大家都在看的(static类),但是每个人手上的平板电脑或者私人物品时不可看到的(非静态类·)

    每个人·都有自己的名字·,但是教师是共用的。

    2. 不存储在对象空间里,存在方法区

    • 普通变量(name):存在 每个对象自己的空间
    • 静态变量(classroom):存在 类的公共空间(方法区) 不管你创建 1 个对象 还是 100 个对象,静态变量只有 1 份!
    • 3. 可以用对象访问,更推荐用类名访问

    Student.classroom = "302教室";//类名访问推荐
    Student s = new Student();
    s.classroom = "302教室";//对象访问不推荐

    静态变量 → 属于类,不属于对象 → 用类名访问!

    4. 生命周期:随类加载而生,随类卸载而死

    • 对象:new 的时候出生,不用了就被回收
    • 静态变量: 程序一运行,类被加载 → 静态变量就出生了 程序结束,类被卸载 → 静态变量才消失

    所以: 静态变量活得比对象久得多!

    静态方法属于类,没有 this;非静态成员 / 方法属于对象,依赖 this,没对象就用不了,所以静态里不能直接调用非静态。

    this 代表当前调用方法的对象,static 不用 new 对象就能执行,不存在 this。

    示例代码

    java

    运行

    public class Student {
    //非静态成员变量(依附对象)
    private String name = "张三";

    //非静态方法,隐含this
    public void show() {
    System.out.println(this.name);
    }

    //静态方法,没有this
    public static void testStatic() {
    // 报错!静态不能直接访问非静态变量
    // System.out.println(name);

    // 报错!静态不能直接调用非静态方法
    // show();

    // 正确用法:手动创建对象,通过对象访问
    Student s = new Student();
    System.out.println(s.name);
    s.show();
    }

    public static void main(String[] args) {
    testStatic();
    }
    }

    原因拆解

  • 非静态方法 show() 底层隐含参数 this
  • java

    运行

    //等价底层:public void show(Student this){}

    调用时:s.show() → 自动把 s 传给 this。

  • 静态方法 testStatic() 没有 this 可以直接 Student.testStatic() 运行,没有对象,传不出 this,没法调用带 this 的非静态方法、没法访问实例变量。
  • 反过来:非静态方法可以随便用静态

    非静态自带 this(有对象),静态属于类,随时可取:

    java

    运行

    public static int num = 100;

    public void normalMethod(){
    //正常运行
    System.out.println(num);
    testStatic();
    }

    口诀

    静态不能直接碰实例,实例随便碰静态;缺对象缺 this,就是根本原因。

  • 静态代码块 → 跟类一起加载,只执行 1 次
  • 构造块(实例代码块) → 每次创建对象就执行,在构造方法前
  • 普通代码块 → 写在方法里,调用方法才执行

  • 二、逐个讲 + 代码演示

    1. 静态代码块(最特殊)

    格式

    java

    运行

    static {
    // 代码
    }

    特点

    • 类一加载就执行
    • 整个程序中只执行 1 次!
    • 用来:初始化静态变量、加载配置、只做一次的准备工作

    例子

    java

    运行

    public class Student {
    static {
    System.out.println("我是静态代码块,只执行一次!");
    }
    }


    2. 构造块 / 实例代码块(常用)

    格式

    java

    运行

    {
    // 代码
    }

    特点

    • 每次 new 对象都会执行
    • 执行时机:在构造方法之前!
    • 用来:所有构造方法都要执行的公共代码

    例子

    java

    运行

    public class Student {
    // 构造块
    {
    System.out.println("我是构造块,每次new对象都先执行我!");
    }

    // 构造方法
    public Student() {
    System.out.println("我是构造方法!");
    }
    }


    3. 普通代码块(最简单)

    格式

    写在方法里面

    java

    运行

    public void test(){
    {
    //普通代码块
    }
    }

    特点

    • 就是方法里的一段代码
    • 调用方法才执行
    • 用来限制变量作用域

    三、终极执行顺序(面试必考!)

    执行顺序:

    静态代码块 → 构造块 → 构造方法 → 普通代码块


    四、超级完整示例(直接运行看结果)

    java

    运行

    public class Student {

    // 1. 静态代码块(最优先,只执行1次)
    static {
    System.out.println("① 静态代码块执行");
    }

    // 2. 构造块(每次new都执行,在构造方法前)
    {
    System.out.println("② 构造块执行");
    }

    // 3. 构造方法
    public Student() {
    System.out.println("③ 构造方法执行");
    }

    // 普通方法 + 普通代码块
    public void study() {
    System.out.println("学习开始");

    // 4. 普通代码块
    {
    System.out.println("④ 普通代码块执行");
    }

    System.out.println("学习结束");
    }

    public static void main(String[] args) {
    System.out.println—–第一次创建对象—–");
    Student s1 = new Student();
    s1.study();

    System.out.println—–第二次创建对象—–");
    Student s2 = new Student();
    }
    }

    运行结果(一定要看!)

    plaintext

    ① 静态代码块执行(只来1次)

    —–第一次创建对象—–
    ② 构造块执行
    ③ 构造方法执行
    学习开始
    ④ 普通代码块执行
    学习结束

    —–第二次创建对象—–
    ② 构造块执行
    ③ 构造方法执行


    五、秒懂总结(背下来就全会了)

  • 静态代码块:类加载执行,只执行 1 次
  • 构造块:每次 new 对象都执行,在构造方法前
  • 普通代码块:写在方法里,调用方法才执行
  • 执行顺序:静态 → 构造块 → 构造方法 → 普通代码块
  • 赞(0)
    未经允许不得转载:171主机测评 » java基础知识--类和对象
    分享到: 更多 (0)

    评论 抢沙发

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