Java类和对象详解

发布于:2025-05-31 ⋅ 阅读:(25) ⋅ 点赞:(0)


1.初步认识

C语言是面向过程的,关注的是过程,分析出解决问题的步骤。而Java是面向对象的,关注的是对象,将事件拆分为多个对象,对象间相互完成一件事件

2.类的定义与实例化

2.1 类的定义

class ClassName{
    variate;    //成员变量
    method;     //成员方法
}

Java中使用class来定义类,ClassName为类名,{}内部为类的主体部分,里面一般包含 成员变量和成员函数

public class MobilePhone {
    public int price;     //成员变量
    public void call(){  //成员函数
        ;
    }
}

注意事项:

  • 一个文件中最好只定义一个类
  • public修饰的类必须和文件名相同

2.2 类的实例化与使用

类是一种自定义类型,其与int,double类似。我们使用int,double来创建变量,而使用类来创建对象,该过程也叫做类的实例化的过程。Java中一般配合new关键字来进行对象的实例化。

public class Dog {
    public String name;
    public String kind;
    public void print(){
        ;
    }
    public static void main(String[] args) {
        Dog dog1=new Dog();   //通过new进行实例化对象
        Dog dog2=new Dog();
        
        dog1.name="小黑";    //访问类的成员
        dog2.name="小白";
        dog1.kind="藏獒";
        dog2.kind="杜宾";
        
        dog1.print();
        dog2.print();
    }
}

类与内置类型非常相似,其只有在实例化出对象后,对应的对象才会占用实际的地址空间

在这里插入图片描述

注意点:

  • 使用 . 来访问类中的成员变量或者成员方法
  • 同一个类可以创建多个实例
  • 实例化出的对象存储的是成员变量,成员方法在方法区中存储。
  • 类是一种引用类型,因此每次实例化对象,都会在堆上的开辟一份空间。

3.this关键字

首先我们定义一个日期类:

public class Date {
    public int _year;
    public int _month;
    public int _day;
    
    public void init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
    public void print(){
        System.out.println(_year+"-"+_month+"-"+_day);
    }

    public static void main(String[] args) {
        Date d1=new Date();
        Date d2=new Date();
        
        d1.init(2025,1,1);
        d2.init(2025,10,1);

        d1.print();
        d2.print();
    }
}

对于上述类,有一个问题是:

Date类中有init和print成员函数,但函数的实现中并未对不同对象进行区分,那么d1调用init函数时,该函数是如何知道应该设置的对象是d1,而不是d2 ?

Java中使用this关键字来处理该问题。 Java中==所有非静态的成员函数(未被static修饰)==均有一个隐含的this引用。

谁调用类中的方法,this就指向谁,函数体内成员变量的访问都是通过this引用进行。

假设Data的成员变量分别为: year,month,day,则

public void init(int year,int month,int day){
        year=year;
        month=month;
        day=day;
}
// 由于局部变量优先,因此此处相当于形参给自己赋值,无法完成初始化。

public void init(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
}
// 使用this可以很好的解决。

因此,在设计成员函数时,使用成员变量最好加上this

4.对象的构造和初始化

4.1 默认初始化

定义时不设置初值,此时会成员变量为其类型的默认值。

就地初始化: 定义的时候直接给出初始值。

public class TestDemo {
    // 默认初始化
    public int x;     //0
    public String s1; //null
 
    public void print(){
        System.out.println("x="+ x+" s1="+s1);
    }
    public static void main(String[] args) {
        TestDemo t=new TestDemo();
        t.print();
}

4.2 就地初始化

声明的同时给出初始值。

public class TestDemo {
    // 就地初始化
    public int y=1;        //1
    public String s2="1";  //1
 
    public void print(){
        System.out.println("y="+ y+" s2="+s2);
    }
    public static void main(String[] args) {
        TestDemo t=new TestDemo();
        t.print();
}

4.3 构造方法初始化

构造方法是一种特殊的成员方法,其在对象的整个声明周期只会被调用一次且在创建对象时由编译器自动调用,主要用来初始化对象。

其特征为:

  • 方法名与类名相同
  • 无返回值
  • 构造方法可以重载
  • 实例化时由编译器自动调用
public class Date {
    public int year;
    public int month;
    public int day;
    public Date(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
    public void print(){
        System.out.println(year+"-"+month+"-"+day);
    }

    public static void main(String[] args) {
        //Date d1=new Date();   报错
        //d1.print();

        Date d2=new Date(2025,5,29);
        d2.print();   //打印2025-5-29
    } 
}

如上注释部分为什么会报错呢?

如果类中未显示的定义给出构造方法,则编译器会自动生成一个无参的默认构造方法,一旦用户显示定义编译器就不会再生成构造方法

IDEA可以快速的定义构造方法:
在这里插入图片描述

构造函数中,可以使用其他构造函数来简化代码:

public class Date {

    public int year;
    public int month;
    public int day;
    
    public Date(){
        this(2025,5,29);
    }
    public Date(int year,int month,int day){
        this.year=year;
        this.month=month;
        this.day=day;
    }
}

5.对象的打印

如何实现默认打印对象中的属性? 重写toString方法

public String toString() {
        return "Date{" +
                "year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
 }

IDEA可以快速实现toString方法的重写:

在这里插入图片描述

6.包的理解

包简单来说就是一个文件夹,文件夹里面有许多类,我们写代码时如果使用了某个类的方法,就需要导入这个包中的对应类。因此,可以说包是一种类的组织方式,提升了可读性以及防止类名冲突。

6.1 导入包中的类

//1. 直接导入指定的包下的类(java,util均为文件夹,Scanner为类)
import java.util.Scanner;
//2. 该导入含义: 用到哪个类就导入哪个类,不是讲util下所有类均导入
import java.util.*;
public class Test {
    public static void main(String[] args) {
        //3. 使用时直接导入,但太麻烦,平时写不推荐
        java.util.Date date=new java.util.Date();
    }
}

并不推荐像方法2式的导入,因为可能会引进冲突。例如: 在util和sql包下均有Date类,那么用Date类时,就不知道该匹配哪个包下的Date类。

使用 import static 可以导入一些静态的方法。

import static java.lang.Math.*;
public class Test {
    public static void main(String[] args) {
        //java.util.Date data=new java.util.Date();
        int x=8,y=16;
        //静态导入有时更加方便些。
        //double result=Math.sqrt(Math.pow(x,2)+Math.pow(y,2));
        double result=sqrt(pow(x,2)+pow(y,2));
    }
}

6.2 自定义包

规则:

  • 包名采用小写
  • 在文件最上方写package语句来指明该文件是哪个包下的,如果未写,则会会放到默认包下。

使用IDEA创建包:

1.右击src -> new -> package

在这里插入图片描述

2.创建Package后,可以选择指定的包,右击 -> new -> calss
在这里插入图片描述

分别在不同级别的包bit,demo1创建类TestBit,TestDemo1,结果:

在这里插入图片描述

6.3 包访问权限

不同于C++,Java的访问权限有四种: public protected private 包访问权限

在定义一个类时,如果成员变量/方法未指定访问权限,则默认为包访问权限。

private: 只允许在类中访问成员,不可以在类外访问。

包访问权限: 必须在一个包下,不同类才能相互访问,如果不同的包,则需要import导入需要的类。

//bit.demo1下的类Computer
package bit.demo1;
public class Computer {
    private String cpu;
    private String menory;
    public String screen;
    String brand;    //未指明访问权限,默认包权限
}
//bit下的类TestBit
package bit;
import bit.demo1.Computer;  //不同包要使用所需的类,需要import指定包下的类
public class TestBit {
    //包访问权限: 只能在同一个包下访问
    Computer cp=new Computer();
    //报错,private: 只允许在类中访问
    //cp.cpu
    //cp.menory
}

:类的访问权限 要么是public 要么不加

7.封装

面向对象程序的三大特性: 封装,继承,多态

封装: 将对象的属性和实现细节隐藏起来,仅通过外部接口来与对象进行交互。

7.1 访问限定符详解

在这里插入图片描述

public修饰: 基本都可以访问

protected修饰: 主要用于继承。

private修饰: 同一个包的同一个类内才能访问。

包访问权限: 同一个包内的才能访问,否则,import导入指定类。

8.static关键字

成员变量分为: 1.静态成员变量 2.非静态成员变量

成员方法分为: 1.静态成员方法 2.非静态成员方法

8.1 修饰成员变量

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

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args) {
        Student s1=new Student("张三",18);
        Student s2=new Student("李四",19);

    }
}

在这里插入图片描述

如上,我们可以发现,被static修饰的成员变量不在对象中了。

实际上, 被static修饰的成员变量也叫做类变量,其不属于某个类,而是被所有类对象共享,存放在方法区,且只有一份

其访问方式为:

// 1.正确方式: 类名.类变量
Student.classRoom="c1";

// 2.可以但不恰当的访问方式: 对象.类变量
// 这种方式会报警告
s1.classRoom="c1";
s2.classRoom="c1";

静态变量的核心特征是其不依赖于对象,不需要实例化对象

8.2 修饰成员方法

与静态成员变量类似,静态成员方法不依赖于对象。其访问方式与类变量基本一致。

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

    public static void print(){
        System.out.println("静态方法");
    }
    public static void main(String[] args) {
        Student s1=new Student();
        //方法一: 对象.静态方法
        //这种写法可以但不恰当,会发生警告,但非常不推荐
        s1.print();
        Student s2=new Student();
        s2.print();
        
        //方法二: 类名.静态方法
        //这是正确访问方法
        Student.print();
    }
}

静态方法是不依赖于对象的,而非静态是依赖于对象的,因此可以推出相关结论:

  • 非静态方法中可以直接调用静态方法,因为静态方法不依赖于对象。
  • 静态方法中不可以直接调用非静态方法,因为非静态依赖于对象,必须先new一个对象才能调用。
  • 静态方法中不能使用this,因为this是哪个对象调用就指向谁,但静态方法不依赖对象,因此不知道指向。
  • 静态方法中无法直接访问非静态的成员变量,因为其是依赖于对象的,因此想调用,必须先new对象。

理解如上结论的关键就是知道: 静态方法是不依赖于对象的,而非静态成员是依赖于对象的

9.代码块

代码块主要有: 1.静态代码块 2.构造/实例化代码块 3.普通代码块 4.同步代码块

9.1 构造代码块

一般用来初始化实例化的成员变量。

public class Computer {
    private String cpu;
    private String screen;
    private static int price;

    {
        cpu="Intel";
        screen="OLED";
        System.out.println("构造代码块");
    }
}

9.2 静态代码块

使用static定义的代码块,一般用于初始化静态成员变量

public class Computer {
    private String cpu;
    private String screen;
    private static int price;
    
    static{
        price=7599;
        System.out.println("静态代码块");
    }
}

9.3 代码块的执行顺序

大体上来说: 静态代码块>实例代码块>构造方法 ,如果是相同级别的代码块,按序执行。

public class Computer {
    private String cpu;
    private String screen;
    private static int price;

    {
        cpu="Intel";
        screen="OLED";
        System.out.println("构造代码块");
    }

    static{
        price=7599;
        System.out.println("静态代码块");
    }

    public Computer(){
        System.out.println("不带参数的构造方法");
    }
    
    public static void main(String[] args) {
        Computer cp=new Computer();
    }
}

//结果:
静态代码块
构造代码块
不带参数的构造方法

注意点:

  • 静态代码块无论生成多少个对象,都只执行一次。
  • 实例代码块在创建类对象时才被执行