【Java SE】封装的详解(下)

简介: 如果把封装的概念放在语言中,那就是:将数据和操作数据的方法进行结合,隐藏对象的属性,和实现细节,仅仅对外公开接口来和对象进行交互。

3.3 static 修饰静态成员方法

上面看完 static 修饰成员变量,但是我们之前都是建议成员变量用 private 来修饰啊,那这样的话如何在类外访问我们静态成员变量呢?

有了上面的问题,所以Java中可以用 static 修饰成员方法,如果被 static 修饰的成员方法,称之为静态成员方法,也可成为类方法,不属于任何一个对象,所以类方法没有隐藏的 this 参数!

这里我们就把上面的 Student 类里面的类变量改为 private 修饰,增加一个获取教室的类方法:

public class Student {
    //这里表示 name age 成员变量只能在 Student 类中访问
    private String name; 
    private int age;
    public static String classRoom = "八年级二班"; //静态成员变量
    public static String getClassRom() {
        return Student.classRom; //类变量,可以通过类名访问,当然在类方法中,也可也省略
    }
}
class TestStudent {
    public static void main(String[] args) {
        Student stu = new Student();
        System.out.println(Student.getClassRoom()); //可以通过类名访问类方法
        System.out.println(stu.getClassRoom()); //也可也通过对象访问类方法,但不推荐
    }
}

注意:

static 修饰的成员方法,可以称为类方法,不属于某个具体的对象,在静态成员内部,不能直接访问任何非静态成员变量和方法,前面也说过原因,如果你非要访问,自己用类实例化一个对象吧,但很少这样做,静态方法不支持重写,不能用来实现多态,这个我们后续多态部分时候讲

3.4 static 成员变量初始化

一般来说,我们静态成员变量不会在构造方法中初始化,而一般有两种初始化的方式,就地初始化和静态代码块初始化:就地初始化就是在定义的时候直接给出初始值,至于静态代码块初始化,我们往后看代码块的相关知识:

4、代码块

4.1 代码块的分类及概念

代码块就是用 { } 定义的一段代码叫做代码块,根据代码块定义的位置以及关键字,可以分为四种:

  • 普通代码块 -> 这里我们不多强调,就是定义在方法中的代码块,很少用
  • 构造代码块
  • 静态代码块
  • 同步代码块(多线程的时候讲解)

4.2 构造代码块和静态代码块

构造代码块,也有构造方法两个字,那他跟构造方法是有一定区别的,构造代码块是定义在类中的代码块(不加修饰符) ,也可称为实例代码块,主要是用于初始化实例成员变量,也就是非静态成员变量。

静态代码块,主要是用来初始化静态成员变量的代码块,我们来看具体演示代码:

public class Student {
    private String name;
    private int age;
    private static String classRoom;
    {
        //这里是构造代码块,也叫实例代码块,一般用于初始化实例成员变量
        this.name = "王五";
        System.out.println("构造代码块执行!");
    }
    static {
        //这里是静态代码块,一般用于初始化静态成员变量
        Student.classRoom = "八年级二班";
        System.out.println("静态代码块执行!");
    }
}
class TestStudent {
    public static void main(String[] args) {
        Student stu1 = new Student();
        Student stu2 = new Student();
    }
}

我们 new 了两个对象,而静态代码块是定义在构造代码块后面的,我们再来看结果执行main方法的结果:

为什么会是这个结果?为什么静态代码块后定义,但是先执行?为什么构造代码块执行了两次?这里我们一一来解释:

  • 实例代码块每次创建对象都会执行一次,静态代码块不管生成多少个对象只执行一次。
  • 静态成员是类的属性,因此是在JVM加载类时开辟空间的,所以静态代码块要比实例代码块先执行
  • 如果一个类包含多个静态代码块,则按照定义的顺序,也就是从上往下执行(合并)

5、内部类

5.1 内部类的概念和分类

什么是内部类?将一个类定义在另一个类或者一个方法的内部,称为内部类,内部类外面的类可以称为外部类,内部类也是封装的一种体现!

内部类必须定义在外部类的 { } 内部,内部类和外部类是共用一个Java源文件,但是编译之后,内部类会形成单独的字节码文件,这个大家可以在编译之后自行查看。

内部类分为两大类:成员内部类(定义位置跟成员所处位置相同),局部内部类(定义在方法体或者 {} 中)

成员内部类包含:实例内部类,静态内部类

局部内部类包含:局部内部类,匿名内部类(抽象类和接口部分讲)

5.2 实例内部类

public class Student {
    private String name;
    private int age;
    private static String classRoom;
    class InnerClass {
        //实例内部类,可以直接访问外部类中:任意访问限定修饰符的成员
        int age = Student.this.age; //如果访问外部类同名的成员,需要使用类名.this.成员名
        String room = Student.classRoom;
        //实例内部类中,不能定义有static修饰的成员,如果非要定义,则需要使用 final 修饰的常量
        //常量是在程序编译的时候确定的,一旦初始化,就不能改变
        private static final int a = 10;
        public void func() {
            //实例内部类的非静态方法中,包含了一个指向外部类对象的引用,所以可以使用this.访问
            this.age = 10;
        }
    }
}

实例内部类就是指没有被 static 修饰的内部类,那么如何实例化内部类呢?

public static void main(String[] args) {
        //方法1
        Student stu1 = new Student();
        Student.InnerClass stu2 = stu1.new InnerClass();
        //方法2
        Student.InnerClass stu3 = new Student().new InnerClass();
    }

方法1,既然是实例内部类它的定义位置是跟外部类的成员位置相同,我们可以先有一个外部类的对象,所以也就可以借助外部类的对象来实例化内部类。

方法2,我们可以直接先实例化外部类,在紧接着通过实例化的外部类再去实例化内部类,这样也是可以的!

总结:

  • 外部类的任何成员都可以在实例内部类中直接访问
  • 实例内部类所以他所处的位置是于外部类成员位置相同的,因此也可以使用public private限定符来约束
  • 在实例方法中,访问相同的成员时,优先访问自己的,如果要访问外部类的,得使用 类名.this.同名成员 来访问
  • 实例内部类非静态方法中,包含了一个指向外部类的对象的引用
  • 实例内部类不能有static修饰的成员,如果非要,需要用 final 修饰(以后讲解)
  • 如果外部类要访问内部类的成员,必须要先有内部类的对象

5.3 静态内部类

public class Student {
    private String name;
    private int age;
    private static String classRoom;
    public static String getClassRoom() {
        return Student.classRoom;
    }
    static class StaticInnerClass {
        //静态类中,可以直接访问外部类的静态成员
        String room = Student.classRoom;
        public void func() {
            String room = Student.getClassRoom();
        }
    }
}

我们创建静态类对象呢?首先既然他是静态的那就说明他不依赖于对象,也就是说,不需要先创建外部对象那我们就可以直接使用外部类类名.内部静态类类名来实例化:

public static void main(String[] args) {
        Student.StaticInnerClass sInClass = new Student.StaticInnerClass();
    }

关于静态类我们还要注意一点:静态类中不能直接访问外部类非静态成员,如果非要访问外部类非静态成员,我们需要先创建外部类对象,这个也交给小伙伴们下去尝试。

5.4 局部内部类

局部内部类也就是定义在外部类的方法体中或者 {} 中,这种内只能在定义的地方使用,一般使用非常的少,因为是局部的,他并不能被public,static等修饰符修饰,他也有自己独立字节码文件:外部类类名$数字内部类类名.class,这种几乎不使用,我们知道有就可以。

最后,内部类主要是出现在库中代码里面,实际开发用的不算很多,用的最多的是匿名内部类,但是这个我们放到抽象类和接口部分介绍。

相关文章
|
1月前
|
安全 Java 编译器
Java的封装详解
封装和多态是面向对象编程(OOP)的重要概念。封装通过私有属性和公共方法实现数据隐藏和保护,使类的内部细节对外部不可见;多态则通过方法重载和重写实现同一方法在不同对象上的不同表现形式,增强了代码的灵活性和可维护性。两者结合使用,可以使Java程序更加安全、灵活且易于维护。
|
1月前
|
Java
Java的封装详解
封装是Java中实现数据隐藏和保护的核心机制。它通过将对象的状态和行为结合并限制外部直接访问,确保类的内部细节对外不可见,仅能通过公共方法访问和修改对象状态。封装带来了数据隐藏、提高代码可维护性和增强安全性等好处。在Java中,封装主要通过将属性设为私有并提供getter和setter方法来实现。这种方式不仅保护了数据完整性,还允许在修改类内部实现时不影响外部代码,从而提升程序的健壮性和可读性。
|
29天前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
1月前
|
SQL Java 编译器
Java——类与对象(封装)
封装是面向对象编程中的概念,指将数据(属性)和相关操作(方法)组合成独立单元(类),使外部无法直接访问对象的内部状态,只能通过提供的方法进行交互,从而保护数据安全。例如,手机将各种组件封装起来,只暴露必要的接口供外部使用。实现封装时,使用`private`关键字修饰成员变量,并提供`get`和`set`方法进行访问和修改。此外,介绍了包的概念、导入包的方式及其注意事项,以及`static`关键字的使用,包括静态变量和方法的初始化与代码块的加载顺序。
36 10
Java——类与对象(封装)
|
1月前
|
安全 Java 数据安全/隐私保护
Java 封装怎么理解
封装是Java中的一种重要机制,它将对象的状态(数据)和行为(方法)打包在一起并控制外部访问权限,以保护数据不被随意修改。封装的主要目的包括数据保护、接口设计和增强模块性。通过使用`private`、`protected`及`public`等访问控制修饰符,结合getter和setter方法,可以有效隐藏对象内部实现细节。下面是一个简单的`BankAccount`类示例,展示了如何通过封装保护类的内部状态,确保数据安全和一致性,简化类的使用。理解封装有助于编写高质量代码和设计优秀程序架构。
|
1月前
|
Java 数据安全/隐私保护
Java 封装详解
在 Java 中,封装是面向对象编程的关键特性,通过将对象的状态(数据)和行为(方法)结合并利用访问控制保护数据,防止外部随意访问和修改。主要特点包括访问控制(如 `private` 和 `protected`)、数据隐藏及方法暴露(如 getter 和 setter)。封装的优点在于保护数据、隐藏实现细节、易于维护以及提高代码可读性。下面是一个简单的 `Person` 类封装示例,展示了如何通过 getter 和 setter 控制对类内部状态的访问,并进行合法性检查。总结而言,封装有助于构建清晰、易用且可维护的代码结构,是编写高质量 Java 程序的重要原则。
|
29天前
|
安全 Java 开发者
Java修饰符与封装:理解访问权限、行为控制与数据隐藏的重要性
Java中的修饰符和封装概念是构建健壯、易维护和扩展的Java应用程序的基石。通过合理利用访问权限修饰符和非访问修饰符,开发者能够设计出更加安全、灵活且高效的代码结构。封装不仅是面向对象编程的核心原则之一,也是提高软件项目质量和可维护性的关键策略。
14 1
|
1月前
|
Oracle Java 关系型数据库
Java(TM) Platform SE binary 已停止工作”的解决方法
Java(TM) Platform SE binary 已停止工作”的解决方法
134 2
|
2月前
|
安全 Java
Java基础面试十四】、 封装的目的是什么,为什么要有封装?
这篇文章讨论了封装在面向对象编程中的目的,强调封装可以隐藏类的实现细节,通过方法控制对数据的访问,保证数据完整性,并提高代码的可维护性。
Java基础面试十四】、 封装的目的是什么,为什么要有封装?
|
2月前
|
缓存 前端开发 Java
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)
【8月更文挑战第10天】java基础巩固,工具类的封装
24 1
【前端学java】java基础巩固复习巩固语法练习-工具类的封装(14)