JavaSE语法(6)——详细解读Java中的类与访问修饰符

发布于:2023-02-17 ⋅ 阅读:(808) ⋅ 点赞:(0)

目录

✏️类定义和使用

1.类的定义格式

2.类的实例化

3.类的内存模型

✏️this引用

1. 引入

2.什么是this引用

✏️构造方法

1.概念及用法

2.this引用在构造方法中的应用

✏️封装

1.访问限定符

2.private

3.包

3.1 概念

3.2 导入包中的类:import

4. 什么都不写的时候的默认权限(default)


✏️类定义和使用

        类是Java程序的基本要素,一个Java应用程序就是由若干类所构成的。类声明的变量被称作对象变量,简称对象(就有点类似于C语言中的结构体)。


1.类的定义格式

        格式:

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

        class为定义类的关键字,ClassName为类的名字,{}中为类的主体。

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

例:

class Cat{
    public String name;
    public String color;

    //猫的叫声
    public void meow() {
        System.out.println(name + ":喵喵喵~");
    }

    //行为
    public void behavior() {
        System.out.println(name + ":舔爪子");
    }
}
 

问题:为什么在方法中能直接用 name 变量呢?

答:name是定义在方法外面的,就类似于C语言中的全局变量,整个类里的方法都可以直接用该变量。(特殊的情况除外,如加了static的方法 等,static关键字的详细介绍后面会更新)。

需要注意的:

//可以在声明的同时指定变量的初值
class A{
    int a = 12;
    float b = 12.33f;
}

//以下是错误的用法
class A{
    int a;
    float b;
    a = 12;           //非法
    b = 12.33f;       //非法
}

注意:

  • 在声明成员变量时如果没有指定初始值,Java编译器会为其指定相应的默认值。
  • 类名注意采用大驼峰定义(首字母大写)
  • 一般一个文件当中只定义一个类。
  • main方法所在的类一般使用public修饰(注意:Eclipse默认会在public修饰的类中找main方法)。
  • public修饰的类必须要和文件名相同。
  • 成员前写法暂时统一为public方法暂时不带 static 关键字。(关于static的详细介绍会在后续更新)

2.类的实例化

        类是用户自定义了一个新的类型,比如上述的:Cat类;用 类 类型创建对象的过程,称为类的实例化。

  • 对象的声明
类的名字 对象的名称;

例:

Cat c;
  • 为声明的对象分配变量

        使用new运算符来创建对象;

public class Main{
    public static void main(String[] args) {
        Cat c = new Cat();
        c.name = "小白";
        c.color = "白色";
        c.behavior();
        c.meow();

        Cat c2 = new Cat();
        c2.name = "小黑";
        c2.color = "黑色";
        c2.behavior();
        c2.meow();
    }
}

 运行结果:

小白:舔爪子
小白:喵喵喵~
小黑:舔爪子
小黑:喵喵喵~

注意:

  • new 关键字用于创建一个对象的实例。
  • 使用“ . ”访问对象中的属性和方法。
  • 同一个类 类型可以创建多个实例。

3.类的内存模型

        类的信息放在了方法区、对象的引用存放在栈中,对象的实例存放在堆中。

JavaSE语法(5)——【数组(基本类型变量与引用类型变量的区别、二维数组、二维数组打印、jvm的内存分布……)】_虾料的博客-CSDN博客https://blog.csdn.net/Che__dan/article/details/127608985?spm=1001.2014.3001.5501关于方法区、栈、堆 ,上面文章有介绍👆。

有如下代码:

public class Main{
    public static void main(String[] args) {
        Cat c = new Cat();
        c.name = "小白";
        c.color = "白色";
        c.meow();
    }
}

class Cat{
    public String name;
    public String color;

    //猫的叫声
    public void meow() {
        System.out.println(name + ":喵喵喵~");
    }
}
  • 当程序开始时,Main类里的信息(成员变量、成员方法)会存到方法区。

4a4803144186497dabcfdc873db49db0.jpeg

  •  当开始执行main方法时,栈里就会开辟一个空间来装main方法(入栈)。

538c944cd1b247b78b013002d10e265c.jpeg

  •  当执行到 Cat c = new Cat() 时,方法区就会加载Cat类的信息,同时在堆中创建Cat的实例,栈里的 c ,存储了堆里的Cat实例的地址;堆里Cat实例中的方法存储了方法区里的方法的地址。

8857b88fd35d4dbab8b4de6260df1e85.jpeg

  •  对成员变量进行赋值后(对字符串赋值涉及到常量池,常量池详细内容后面更新),执行到c.meow()时,通过地址获取到方法区里的meow方法的信息,然后在栈里开辟一个空间。

55735e257e274c07b8e266668230bf33.jpeg



✏️this引用


1. 引入

class Student{
    public int age;
    public int height;

    public void set(int a, int h){
        age = a;
        height = h;
    }
    public void print(){
        System.out.println("age: " +age +  " height: " + height);
    }
}

public class Main{
    public static void main(String[] args) {

        Student s1 = new Student();
        Student s2 = new Student();
        //输入年龄、身高
        s1.set(18,180);
        s2.set(20,184);
        //打印
        s1.print();
        s2.print();
    }
}

结果:

age: 18 height: 180
age: 20 height: 184

        输出没问题,但是我们把set()里的参数改一下

class Student{
    public int age;
    public int height;
    
    //改成 age height
    public void set(int age, int height ){
        age = age;
        height = height;
    }
    public void print(){
        System.out.println("age: " +age +  " height: " + height);
    }
}

public class Main{
    public static void main(String[] args) {

        Student s1 = new Student();
        Student s2 = new Student();
        //输入年龄、身高
        s1.set(18,180);
        s2.set(20,184);
        //打印
        s1.print();
        s2.print();
    }
}

        这时Student里的成员变量的值是什么?

结果:

age: 0 height: 0
age: 0 height: 0

        发现age与height的值并没有改变,是因为set的形参与成员变量名相同了,这时set方法里的age与height不算Student的成员变量,而是算作形参了,要避免这一现象,就可以用this关键字。


2.什么是this引用

        this表示某个对象,this引用指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问。

        以上面的例子:

class Student{
    public int age;
    public int height;
    
    //改成 age height
    //加了this
    public void set(int age, int height ){
        this.age = age;
        this.height = height;
    }
    public void print(){
        System.out.println("age: " +this.age +  " height: " + this.height);
    }
}

public class Main{
    public static void main(String[] args) {

        Student s1 = new Student();
        Student s2 = new Student();
        //输入年龄、身高
        s1.set(18,180);
        s2.set(20,184);
        //打印
        s1.print();
        s2.print();
    }
}

结果:

age: 18 height: 180
age: 20 height: 184

注意:

  • this的类型:对应类类型引用,即,哪个对象调用就是哪个对象的引用类型。
  • this只能在"成员方法"中使用(加了static的方法不行,后续更新)。
  • 在"成员方法"中,this只能引用当前对象,不能再引用其他对象。
  • this也可以调用该类的方法,就跟调用变量一样。

  • this是“成员方法”第一个隐藏的参数,编译器会自动传递,在成员方法执行时,编译器会负责将调用成员方法对象的引用传递给该成员方法,this负责来接收。

        例:在set方法的形参列表里加一个“Student this”。

58fb1b175eae4990a7246ee50d38f4c4.png

 结果:

91d5a8b555a54d2b875062bda27a1eab.png

         能编译过,说明this就是本类的引用。



✏️构造方法


1.概念及用法

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

class Student{
    public int age;
    public int height;

    // 构造方法:
    // 名字与类名相同,没有返回值类型,设置为void也不行
    // 一般情况下使用public修饰
    // 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
    public Student(int age,int height) {
        System.out.println("构造方法被调用了!!!");
        this.age = age;
        this.height = height;
    }
    public void print(){
        System.out.println("age: " +age +  " height: " + height);
    }
}

public class Main{
    public static void main(String[] args) {
        //输入初始值
        Student s1 = new Student(18,182);

        s1.print();
    }
}

结果:

构造方法被调用了!!!
age: 18 height: 182

注意:

  • 构造方法的参数有几个,new的时候就要输入几个参数,否则会报错。

9d7ec0d14648490d97043eabead6bebb.png

  • 没有写构造方法的时候,编译器会自动生成一个无参数的构造方法(并且不会显示),如果写了就不会生成,这也是为什么上一条会报错的原因。

  • 构造方法可以重载!当我们既想在new的时候不输入参数不报错,又想输入参数,那么就可以重载构造方法。
class Student{
    public int age;
    public int height;

    // 构造方法:
    // 名字与类名相同,没有返回值类型,设置为void也不行
    // 一般情况下使用public修饰
    // 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
    public Student() {
        System.out.println("无参的构造方法被调用了!!!");
        //也可以在这里对age 和 height 赋值
    }

    public Student(int age,int height) {
        System.out.println("有参的构造方法被调用了!!!");
        this.age = age;
        this.height = height;
    }
    public void print(){
        System.out.println("age: " +this.age +  " height: " + this.height);
    }
}

public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.print();

        Student s2 = new Student(18,180);
        s2.print();
    }
}

结果:

无参的构造方法被调用了!!!
age: 0 height: 0
有参的构造方法被调用了!!!
age: 18 height: 180

2.this引用在构造方法中的应用

        this可以调用其他构造方法,格式:" this() ",因为this就是Student的引用,可以把this看作Student。
 

class Student{
    public int age;
    public int height;
    
    public Student() {
        this(12,181);
    }

    public Student(int age,int height) {
        System.out.println("有参的构造方法被this调用了!!!");
        this.age = age;
        this.height = height;
    }
    public void print(){
        System.out.println("age: " +this.age +  " height: " + this.height);
    }
}

public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.print();
    }
}

结果:

有参的构造方法被this调用了!!!
age: 12 height: 181

注意:

  • this(...)必须是构造方法中第一条语句,不然会报错。

dc8464c36d0d41e58826dde61e8729e6.png

  •  不能形成环。

ea5661155ad84fc29e043e48d087287d.png



✏️封装


1.访问限定符

        在前面我们都是用public来修饰方法、变量、类,这有什么玄机呢?

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

983123e8529f4a3681ca62a8e5bf3595.jpeg

  • public:可以理解为一个人的外貌特征,谁都可以看得到。
  • default(什么都不写的时候的默认权限):对于自己家族中(同一个包中)不是什么秘密,对于其他人来说就是隐私了。
  • private:只有自己知道,其他人都不知道。

 注意:

  • protected主要是用在继承中。(更新继承的时候再来详细介绍,本篇就不介绍了)
  • default 权限指:什么都不写时的默认权限!!!
  • 访问权限除了可以限定类中成员(包括方法)的可见性,也可以控制类的可见性。

2.private

        看下面代码:

class Student {
    private int age;
    private int height;
    
    public void print() {
        System.out.println("age: " + this.age + " height: " + this.height);
    }
}


public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.age = 18;
        s1.height = 184;
    }
}

结果:

79798e29137448b8a3c64e091a2affd6.png

         可以看到报错了,是因为private只能在同一个类中才能被访问到,那么有什么方法可以改变age 和 height 呢?

        我们可以用public修饰的方法来修改其值,这其实体现着封装的思想。

class Student {
    private int age;
    private int height;

    public int getAge() {
        return age;
    }

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

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public void print() {
        System.out.println("age: " + this.age + " height: " + this.height);
    }
}


public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setAge(18);
        int age = s1.getAge();
        System.out.println(age);

        s1.setHeight(180);
        int height = s1.getHeight();
        System.out.println(height);

        s1.print();
    }
}

结果:

18
180
age: 18 height: 180

        我们可以用setAge()、setHeight()来赋值,getAge()、getHight()来取值。


3.包

3.1 概念

        为了更好的管理类,把多个类收集在一起成为一组,称为软件包。

        包是Java语言有效地管理类的一个机制。在不同Java源文件中可能出现名字相同的类,如果用户想区分这些类,就需要使用包名。使用包名可以有效地区分名字相同的类,当不同Java源文件中的两个类的名字相同时,它们可以通过隶属于不同的包来相互区分。

3.2 导入包中的类:import

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

public class Main{
    public static void main(String[] args) {
        java.util.Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

        但是这样操作太复杂了,我们直接用import来导入包:

import java.util.Date;

public class Main{
    public static void main(String[] args) {
        Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

        如果我们还想使用 util 里其它的类,比如:Arrays类。这时可以用“ * ”:

import java.util.*;
public class Main{
    public static void main(String[] args) {
        Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
        
        int[] arr = {5,4,3,2,1};
        Arrays.sort(arr);
    }
}
  • 注意:这样使用也有风险!!!
import java.util.*;
import java.sql.*;
public class Main{
    public static void main(String[] args) {
        Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
    }
}

结果:

e9963d8694b143f6892cb37eb7773bb0.png

         在util 和 sql 中都有Data这个类,这时会冲突,这就需要写详细一点了。

4. 什么都不写的时候的默认权限(default)

        创建了两个包、并在里面写了不同的类:

9267631d0a17405fb2201ecaca741e3e.png

demo2包:

package demo2;

public class Student {
    
    //什么修饰符都没写
    int age;
    int height;

    public void print() {
        System.out.println("age: " + this.age + " height: " + this.height);
    }
}

 demo1包:

package demo1;

//导包中的类
import demo2.Student;

public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.age = 18;
        s1.height = 180;
        s1.print();
    }
}

结果:

2c00dad1e34c469fa40a283131db4e5c.png



同一个包 demo1:

6feadd42434947209b73950d8a6bf89d.png

 结果(代码一样):

age: 18 height: 180


修饰类的情况:

c024411dbec5499fbbb909534d4591bd.png

demo2:

package demo2;

//该类没有写修饰符,即为默认的权限
class Student {
    int age;
    int height;

    public void print() {
        System.out.println("age: " + this.age + " height: " + this.height);
    }
}

 demo1:

package demo1;

import demo2.Student;

public class Main{
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.age = 18;
        s1.height = 180;
        s1.print();
    }
}

结果:

6e24deea1b2c4e52983acf623686839c.png

总结:什么都不写的时候的默认权限(default),只有在同一个包中才能被访问到。不只是变量,修饰符加在方法、类上都是一样的,而public权限在什么地方都能被访问,就不介绍了。

本文含有隐藏内容,请 开通VIP 后查看