Java——类和对象

        之前已经详细介绍过了C++的类和对象的相关知识,这一篇博客重点对Java中的类进行介绍,同时也会与C++中的类的特点和使用方法做以类比。

1. 类的基本操作

1.1 类的定义格式

        在java中对于类的创建使用class关键字,其中包含成员变量和成员方法。

//创建一个Book类
class Book{
    //成员变量(属性)
    public String Title;
    public double price;

    //成员方法(行为)
    public void readBook()
    {
        System.out.println("读书");
    }
}
注意点:

①一般只在一个源文件中定义一个类,不建议一个java文件多个类。

②每个类在编译后都会产生一个字节码文件。

③一般而言,main方法所在的类需要由public修饰,且public修饰的类需要和文件名相同。

1.2 类的实例化与访问

        在定义了一个类后,需要使用关键字new对对象进行实例化(对于C++来说类的实例化不需要new的参与)。实例化后的对象和我们之前所介绍的引用变量一样,其对象仅仅存储了一个地址,而真正的数据存储在这个地址所指向的空间。

        类的访问通过实例化的对象进行成员变量和成员方法的访问。

    public static void main(String[] args) {
        Book b1 = new Book();
        b1.Title = "高等数学";
        b1.price = 55.3;
        b1.readBook();
    }

2.this引用

       在java的非静态成员方法中存在this引用,当一个对象调用了成员方法,那么这时this引用就可以视为这个对象在方法内的替身,调用对象的成员变量都需要通过this指针来访问。this指针对用户透明,由编译器自动完成,无需手动传参。

class Date{
    public int year;
    public int month;
    public int day;
    public void setDate(Date this,int year,int month,int day){
        this.year = year;
        this.month = month;
        this.day = day;
    }
}
注意点:

①this的作用在java和c++中是非常相似的,但是需要注意细节。this在java中是对象的引用,所以使用时使用 . 操作符。而c++中的this是一个类类型的指针,所以使用时需要 -> 操作符

②this的值不可变。可以通过this修改成员变量,但是不可以直接修改this。这一点在java和c++中是一致的。

③this在调用非静态成员方法时会自动传参,在java中,实参位置处不可以写出,在形参位置处则允许显式写出。而c++是均不允许写出,只允许使用。

④对于c++使用习惯是尽量不使用this,而习惯将成员函数命名与参数命名进行区分。而java中习惯频繁使用this引用,java中也可以不用this而使用命名区分。

3. 对象的构造与初始化

3.1 构造方法

        在java的类中存在构造函数,它的作用就是帮助我们对新创建的对象进行初始化。

class Time{
    public int hour;
    public int minute;
    public int second;

    //无参构造函数
    public Time(){}
    //带参构造函数
    public Time(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
}
注意点:

        对于构造函数,其大体与c++一致,不过我们依旧对其进行总结与腔调:

①和c++一致,构造函数在我们没有实现的时候会由编译器默认生成一个无参的构造函数,而当我们写了任何一种构造函数后都不会再自动生成

②和c++一致,构造函数的函数名与类名相同没有返回值,也没有返回类型(c++的构造函数返回类型void可以不写),允许重载

③和c++一致,构造函数会在实例化对象时自动调用,并且在这个对象的生命周期中仅调用这一次。

④java独有的,可以在构造函数内使用this(...)对其他构造函数进行调用。this(...)必须是构造方法的第一条语句,根据参数类型和个数进行调用。在执行完调用的构造后不直接返回,会继续执行该构造中的剩余代码。需要注意调用不可以成环,即相互调用陷入死循环。

    public Time(){
        System.out.println("Time()");
    }
    //带参构造函数
    public Time(int hour, int minute, int second) {
        this();
        System.out.println("Time(int,int,int)");
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

3.2 对象的初始化

        对象在被new了之后,首先会被分配空间。分配完空间之后,对分配的空间进行初始化,这次初始化是默认初始化,一定会发生的,会将不同数据类型初始化为不同的值,引用类型为null,boolean类型为false,其余类型均为其自己形式的0。

        在这次默认初始化后,会进入就地初始化,即使用成员变量声明时给出的初始值来初始化。实际上在编译完成后,就地初始化语句就被会添加到各个构造方法中。

        完成了以上所有的操作后,才会调用构造方法,对成员进行赋值。

class Time{
    public int hour=12;
    public int minute;
    public int second=90;
    public Date d;

    //无参构造函数
    public Time(){
        System.out.println("Time()");
    }
    //带参构造函数
    public Time(int hour, int minute, int second) {
        this();
        System.out.println("Time(int,int,int)");
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }
}
public class Test {
    public static void main(String[] args) {
        Time t1 = new Time(154,1,1);
        System.out.println(t1.hour);    //154
        Time t2 = new Time();
        System.out.println(t2.hour);    //12
        System.out.println(t2.minute);  //0
    }
}
注意点:

        对初始化部分进行总结比较:

①java的初始化逻辑:默认初始化boolean类型是false,引用类型是null,其余类型是0)->就地初始化(使用声明时给出的初始值)->构造方法

c++的初始化逻辑:初始化列表(值来源于:给定值——初始化列表成员变量后面括号中的值->缺省值——在声明处给出->随机值)->构造函数函数体

②和c++不相同,由此我们就可以推得java对于对象,无论是基本类型还是引用类型都会进行默认初始化,而不是像c++一样对内置类型不处理,对自定义类型调用其构造函数。

③因为存在默认初始化,所以直接使用未被用户初始化的成员变量才不会报错,这和使用未初始化的变量报错不冲突,局部变量是不会有默认初始化的。

4. 封装

        我们在c++中已经对封装有了一些基本的认识了,在Java中实现封装主要还是依靠访问限定符。除此之外

4.1 访问限定符

        访问限定符有四种:

        public:在任何地方都可以访问,一般类中的方法多用public;

        protected:暂时不做介绍;

        default:默认权限,当什么访问限定符都不写的时候认为是该默认权限;

        private:只能在类中访问,一般成员变量多用private。

        访问限定符除了可以修饰类的成员变量和成员函数,也可以修饰类。

4.2 包

        包,即软件包,为了更好的管理类,把多个类收集在一起就组成了包。java中的包可以帮助我们更好地组织类和接口,不同包可以通过访问限定符限制权限,并且不同的包中允许同名的类存在。

4.2.1 导入包中的类

        在java中,可以将包理解为一个文件夹,而导入的包中的类实际上就是文件夹下的一个类。在导入对应包的类时有两种方法:在语句中导入和import语句。

//import语句
import java.util.Date;

public class Test2 {
    public static void main(String[] args) {
        //导入java.util包中的Date类
        java.util.Date date = new Date();
        //得到时间戳
        System.out.println(date.getTime());
    }
}
注意点:

①可以使用通配符导入包中的所有类,如:import java.util.* 。

②当导入的所有包中存在命名冲突的类,则必须使用完整的类名在语句中导入。

③使用import static可以只导入包中的静态的方法和成员变量,方便使用。

import static java.lang.Math.*;
public class Test2 {
    
        public static void main(String[] args) {
            double x = 10;
         // double result = Math.sqrt(Math.pow(x, 2));
            double result = sqrt(pow(x, 2));
            System.out.println(result);
        }
}

4.2.2 自定义包

        可以在IDEA中右键src进行新建包,包名以.作为分割符,即 xlz.pack.l4 为 xlz\pack\l4 。然后就可以在这个包下新建输入这个包的类文件了,在包中的java文件会在最上方加上一个package语句指出在哪个包中。

package xlz.pack.l4;

public class MyCl {
}

 5.static成员

        和C++一样,java中由static修饰的成员被称为静态成员,不再属于某一个对象,而是属于类,被所有的对象所共享。可以通过对象访问,也可以通过类名访问,static成员受到访问限定符的约束。

        和C++一样,静态方法没有this参数,所以不可以在静态方法中访问任何非静态成员变量,也不可以调用任何非静态方法。

        和C++不同,java的静态成员变量可以就地初始化或使用静态代码块初始化。

class Man{
    private int age;
    private String name;
    private static String sex = "male";

    public static void printSex()
    {
        System.out.println(sex);
    }
}
public class Test3 {
    public static void main(String[] args) {
        Man.printSex();
    }
}

6. 代码块

        代码块分为:普通代码块,构造代码块(实例代码块),静态代码块,同步代码块。代码块使用大括号包裹。普通代码块没有什么特殊之处,我们略过。

        构造代码块:用于初始化实例成员变量。定义在类中,不使用修饰符。

        静态代码块:用于初始化静态成员变量。定义在类中,使用static修饰符。

class Student{
    private String name;
    private int age = 15;
    private double score;
    private static String school = "ACC university";
    private static String nation;

    public Student(){
        System.out.println("Student()");
    }

    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
        System.out.println("Student(String,int,double)");
    }

    {
        this.name = "AK";
        this.age = 25;
        System.out.println("{构造代码块1}");
    }
    static{
        school = "ABC college";
        System.out.println("static{静态代码块1}");
    }

    {
        this.score = 60.3;
        System.out.println("{构造代码块2}");
    }
    static {
        System.out.println("static{静态代码块2}");
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
    public static String getSchool()
    {
        return school;
    }
    public static String getNation()
    {
        return nation;
    }
}
public class Test4 {
    public static void main(String[] args) {
        Student s1 = new Student();
        Student s2 = new Student("ac",33,84.1);
        System.out.println(s1.toString());
        System.out.println(s2.toString());
        System.out.println(Student.getSchool());
        System.out.println(Student.getNation());
    }
}

static{静态代码块1}
static{静态代码块2}
{构造代码块1}
{构造代码块2}
Student()
{构造代码块1}
{构造代码块2}
Student(String,int,double)
Student{name='AK', age=25, score=60.3}
Student{name='ac', age=33, score=84.1}
ABC college
null

        根据以上测试,做以总结:

①多个构造代码块或静态代码块最终会合并为一个,依次执行。

②静态代码块为静态成员变量赋值,所以只会在最初执行一次;构造代码块为对象初始化,所以在每次创建对象的时候会执行一次,类似于构造方法。

③在这里可以看出初始化顺序

对于静态成员变量:(1) 默认初始化;(2)就地初始化:静态代码块初始化。

※需要强调的一点是,类中对static成员变量的声明也可以看作静态代码块的一部分,在初始化时也会合并,所以静态变量最后初始化的值取决于整个静态代码块执行的结果。

对于非静态成员变量:(1)默认初始化;(2)就地初始化;(3)构造代码块初始化;(4)构造方法初始化。

7. 打印对象

        当我们打印对象的时候,如果直接使用 System.out.println(s1); 来打印对象信息时,会发现输出内容为 Student@1b6d3586 。这是因为在print对象的时候,实际上是调用了对象所在类的toString方法,该方法返回了一个字符串作为打印的字符串。在我们没有实现的时候,编译器会提供一个toString方法完成打印,如上内容就是这个提供的方法打印出的结果。

        如果想要打印自己想要的内容,只需要在类中实现toString的重写即可。

  • 14
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

犀利卓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值