java 类与对象

类的定义

在面向对象编程中,类(Class)是一种定义对象属性(变量)和行为(方法)的蓝图或模板。类是创建对象的基础,它定义了对象的状态(属性)和行为(方法)。每个对象又具有独特的标识、状态、行为。

状态(属性):又叫做末特征,或者属性。使用数据域进行表示。java中使用变量定义数据域。

行为(方法):又叫动作。调用对象一个方法就是要求对象完成一个动作。在java中,使用方法来定义动作。

在现实世界中,“学生”就是抽离出来的一个类,而一些具体的学生名字“张三、李四”等就是一个个实例。

一个对象是类的一个实例。可以从一个类中创建多个实例。创建实例的过程称为实例化。

package cdtestc2020;

/**
 * 每个对象都具有自己独特的标识、状态和行为
 *    状态也称为属性或者特征。用数据域(成员变量)描述
 *       行为也称为动作。通过成员方法描述
 * 使用类描述同一类型的对象
 * 类是对象模板、蓝本或者说是合约。用来定义对象的数据域是什么以及方法是做什么的
 */
public class Circle {
    //通过数据域描述对象的属性(状态)
    public double radius;
    
    /**
     * 构造方法在使用new关键字创建对象时被调用
     *         构造方法作用:一般用作对象的初始化
     * 构造方法是一种特殊的方法:
     * 1、构造必须具有和所在类形同的名字(必须和类名相同)
     * 2、构造方法没有返回值类型,连void都没有
     * 3、使用new创建对象时会调用构造方法,作用为初始化对象
     * 
     * 构造方法也可以进行重载
     * 
     * 如果类中没有定义构造方法,编译器会自动添加一个公共的无参的构造方法(默认),如果已经定义了构造方法,编译器不再添加
     * 一般构造定义在数据域下
     */
    public Circle() {
        System.out.println("调用无参构造方法");
                radius = 1;
    }
    public Circle(double newRadius) {
        System.out.println("初始化圆的半径为:" + newRadius);
        radius = newRadius;
    }
    /**
     * 成员方法描述对象的行为:动作(计算圆的面积)
     * @return 圆的面积
     */
    public double getArea() {
        return 3.14 * radius * radius;
    }
    
    /**
     * 对象的行为/动作
     * 调用一个对象的方法就是要求对象完成一个动作
     * @return 该圆的周长
     */
    public double getPerimeter() {
        return 3.14 * 2 * radius;
    }

}

而instance是对象实例,instance是根据class创建的实例,可以创建多个instance,每个instance类型相同,但是各自的属性可能不同。

package cduestc2020;

public class CircleTest {
    public static void main(String[] args) {
        Circle circle1 = new Circle();//调用的对应的构造方法
        double perimeter1 = circle1.getPerimeter();
        System.out.println(circle1 + "==>radius:" + circle1.radius + "==>area:" + circle1.getArea() + "==>perimeter:" + perimeter1);
        
        Circle circle2 = new Circle(25);
        System.out.println(circle2 + "==>radius:" + circle2.radius + "==>area:" + circle2.getArea() + "==>perimeter:" + circle2.getPerimeter());
        
        Circle circle3 = new Circle(125);//调用的对应的构造方法
        System.out.println(circle3 + "==>radius:" + circle3.radius + "==>area:" + circle3.getArea() + "==>perimeter:" + circle3.getPerimeter());
    }
}

要想使用对象,就必须先构造对象并指定其初始状态,可以通过使用new操作符从构造方法中创建一个对象。

在以上的案例中,数据域(成员变量)redius称为实例变量。因为它依赖于某个具体的实例,同样的,像getArea()以及getPerimeter()等方法被称为实例方法。

成员方法

又叫做实例方法,需要在调用之前创建其类的对象的方法。

因为我们在实例上要使用它。调用对象上的实例方法的过程就叫做调用对象。

构造方法

用来初始化对象的方法。

使用构造方法构造对象的几点注意事项:

  • 构造方法在使用new操作符创建对象时被调用。
  • 构造方法必须具备和所在类同名。
  • 构造方法没有返回值类型,不需要使用void修饰符。
  • 构造方法的作用就是初始化对象。

构造方法也可以进行方法重载(也就是说可以有多个同名构造方法,但是他们的参数不一样),这样就更利于用不同的初始数据值来构造对象。一个类可以没有构造方法,在这种情况下,编译器会自动添加一个方法为空的公公共无参数构造方法,这个构造方法被称为默认构造方法。当且仅当类中没有明确定义任何的构造方法时才会自动提供它。

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

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

    // 成员方法
    public void introduce() {
        System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
    }
}
 //在以上的例子中,person类中有一个构造方法person,它接受两个参数:age 、name。
 //在这个构造方法中,我们可以使用this关键字来区别成员变量和构造方法的参数。

既然有了构造方法,那么怎么使用这个构造方法呢?

public class Main {
    public static void main(String[] args) {
        // 使用构造方法创建Person对象
        Person person = new Person("Alice", 30);

        // 调用成员方法
        person.introduce();
    }
}
//首先要创建一个对象,即初始化对象。传入参数。
//再使用introduce方法来打印出这个对象的自我介绍。

成员方法(实例方法)和构造方法的区别:

方法名称不同

 

  • 构造方法在创建对象时自动调用,不需要显式调用。
  • 成员方法需要显式调用,通常通过【对象名.方法名】的方式调用。

调用方式不同

  • 构造方法在创建对象时被调用,用于创建对象时初始化成员变量。
  • 成员方法用于操作对象的状态或执行特定的任务。

用途不同

  • 构造方法用于初始化对象的状态,通常包含对成员变量的赋值操作。
  • 成员方法用于执行特定的操作,如计算、数据处理、逻辑判断等。

方法体不同

  • 构造方法没有返回值,甚至连void也没有。
  • 成员方法可以有返回值,也可以没有返回值(有viod)。

返回类型不同

  • 成员方法的名称可以任意,只要它符合Java的命名规则
  • 构造方法的名称必须与类名完全相同。

 

静态变量staitc

静态变量又叫类变量,静态变量将变量值存储在一个公共的内存地址,被类中的所有对象所共享。

静态常量 static final

类中的常量是被该类的所有对象所共享的。因此,常量应该声明为final static,例如,Math类中的常量PI是如下定义的:

    pulbic final static double PI = 3.1415926538979323846;

静态方法

不需要创建类对象就可以调用的方法。

在下面两种情况下可以使用静态方法:

  • 方法不需要访问对象状态,因为它需要的所有参数都通过显式参数提供(例如:Math.pow)。
  • 方法只需要访问类的静态字段(例如:Student.getNextId)。

访问修饰符

public : 任何其他类都可以访问使用该修饰符的类、方法或变量。最宽松的访问级别。

default(没有修饰符):在同一个包内的其他类可以访问使用该修饰符的类、方法或变量。这是默认的访问级别,当没有指定任何访问修饰符时,就隐含了default访问级别。

protected :允许子类访问父类中的数据域或方法,但不允许非子类访问这些数据域和方法。

private : 限定方法和数据域只能在自己的类中访问,即只能被本类访问。

 

数据域封装

为了避免对数据域的直接修改,应该使用private修饰符将数据域声明为私有的,这称为数据域封装。在定义私有数据域的类外的对象是不能访问这个数据域的。

为了能够访问私有数据域,可以提供一个访问器返回数据域的值(get方法)。为了更新一个数据域,可以提供一个修改器给数据域设置新值(set方法)。

【当一个类的数据域被声明为private时,这意味着这些域只能在类的内部被访问和修改。为了允许外部代码安全地访问和修改这些私有数据域,通常会提供公共的访问器(getter)和修改器(setter)方法。】

封装通常通过以下方式实现:

  • 使用private访问修饰符来声明数据域,这样只有类内部的方法可以访问它们。
  • 提供公共的getter和setter方法来访问和修改数据域的值。
public class Student {
    /**
     * 学生id,用于唯一标识该学生
     */
    private int id;
    /**
     * 下一个id号
     */
    private static int nextId;
    /**
     * 学生姓名
     */
    private String name;
    
    {
        id = nextId++;
    }
    public Student() {
        
    }
    public Student(String name) {
        this.name = name;
    }
    /**
     * 实例域id的访问器
     * @return id实例域值
     */
    public int getId() {
        return id;
    }
    /**
     * 实例域id修改器
     * @param id id值
     */
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public static int getNextId() {
        return nextId;
    }
}

向方法传递对象参数

在java中,可以向方法传递对象作为参数。当对象作为参数传递时,实际上传递的是对象的引用(reference),而不是对象的实际副本。这意味着方法内部可以修改原始对象的状态。

下面是一个实例:

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

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

    // getter和setter方法
    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;
    }

    // 打印学生信息的方法
    public void printStudentInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}
  //测试类main
public class Main {
    public static void main(String[] args) {
        // 创建一个Student对象
        Student student = new Student("Alice", 20);

        // 调用方法,传递Student对象作为参数
        printStudentInfo(student);

        // 打印原始对象的信息,以验证方法内部是否修改了状态
        System.out.println("After method call:");
        student.printStudentInfo();
    }

    // 接收Student对象作为参数的方法
    public static void printStudentInfo(Student student) {
        // 修改对象的状态
        student.setName("Bob");
        student.setAge(21);

        // 打印修改后的信息
        student.printStudentInfo();
    }
}

在以上的例子中,在这个例子中,Student类定义了一个printStudentInfo方法,用于打印学生的信息。

在Main类中,我们创建了一个Student对象student,然后调用了printStudentInfo方法,并将student对象作为参数传递。在printStudentInfo方法中,我们修改了传递进来的Student对象的状态,将名字改为"Bob",年龄改为21。

然后,我们调用了student对象的printStudentInfo方法来打印修改后的信息。由于对象是通过引用传递的,所以原始对象student的状态在方法调用后确实被修改了。这就是为什么在方法内部修改对象状态(属性)时,需要小心处理,以避免意外的副作用。

针对基本数据类型,传递的是基本数据类型值。

针对引用数据类型,传递的是引用。

不可变对象和类

通常情况下,对象创建之后其内容是可以改变的。但是有时候我们需要对象一旦创建之后其内容不能被更改,称这种对象就叫做不可变对象,它的类就是不可变类。

比如String类就是不可变的。要想使一个对象成为不可变对象,需要满足以下条件:

  • 所有数据域都是私有的。
  • 没有修改器方法。(setter)
  • 没有一个返回指向可变数据域的引用的访问器方法。
import java.util.Date;

public class Employee {
    private static int nextId;
    private int id;
    private String name;
    private Date hireDate;
    public Employee(String name) {
        this.id = nextId;
        nextId++;
        this.name = name;
        this.hireDate = new Date();
    }
    public int getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public Date getHireDate() {
        //返回的是Date对象的一个引用。通过这个引用可以改变hireDate的值
        //return hireDate;
        //可以修改为:
        return (Date)hireDate.clone();
    }
        
}

 

成员变量和局部变量

共同点:

  • 都是变量,他们的定义形式相同:【类型】 【变量名】 = 【初始化值】;
  • 都有作用域:作用域是在一对大括号内

不同点:

内存中存放的位置不同

  •  成员变量存放在堆空间内
  •  局部变量存放在栈空间内

声明的位置不同(作用域不同)

  •  成员变量声明在类的内部,方法的外部,作用整个类;
  •  局部变量声明在方法的内部,从它声明的地方开始到包含它最近的块结束。

 初始化值不同

  •  成员变量可以不赋初值,其默认值按照其数据类型来定
  • 局部变量必须显式地赋初值

 权限修饰符不同

  • 成员变量的权限修饰符有四个:public (default) protected private
  • 局部变量没有权限修饰符,其访问权限依据其所在的方法而定(与方法的访问权限相同)。

 

用var声明局部变量

在Java 10中,如果可以从变量的初始值推导出它们的类型,那么可以用var关键字声明局部变量,而无须指定类型。例如,可以不这样声明:

  Circle circle = new Circle(10);

  只需要写以下代码:

  var circle = new Circle(10);

  这一点很好,因为这样可以避免重复写类型名Circle。

this关键字

接下来我们用一个例子来说明一下:

public class Account {
    private String name;
    private double balance;
    private String pwd;
    
    //Account类的一个构造器
    public Account (String name,double balance,String pwd){
        //构造器的实现---初始化对象
        this.name = name;
        this.balance = balance;    
        this.pwd = pwd;
    }
}

假如我们不按照上面的代码进行操作,如果我们不使用this关键字会怎么样???????

class Account {
    private String name;
    private double balance;
    private String pwd;

    //Account类的一个构造器
    public Account(String name, double balance, String pwd) {
        //构造器的实现---初始化对象
        //不用this
        name = name;
        balance = balance;
        pwd = pwd;
    }

    public void showInfo() {
        System.out.println("name:" + name + " " + "balance:" + balance + " " + "pwd:" + pwd);
        return;
    }
}

public class Main {
    public static void main(String[] args) {
        Account account = new Account("Yaoyao", 20, "123456");
        account.showInfo();
    }
}

其运行结果如下:

解释一下,因为我们错误的认为 name = name 左边的name是成员变量,但是实际上等号左右都是局部变量,因此此句代码就是将局部变量的值赋给局部变量。然而成员变量的值忆旧没有发生改变,仍然是默认值。

因此我们使用this.属性区别成员变量和局部变量。

那么this究竟是什么呢?

  • this可以理解为一个对象的属性(成员变量),但是这个属性是隐藏的。
  • 和其他对象的属性一样,在进行new创建对象时,会在堆为对象分配空间,而属性就是存储在这个空间中,且this属性的值也存储在这个空间内存地址中。即this指向该对象。

综上所述。this是对象的隐藏属性,也就是一个普通的成员变量。在创建对象时会为每个新对象分配该对象的专属成员变量(this就是其中的一个),this这个成员变量就存储在堆内存中。

 

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值