Java 基础之面向对象【类和对象】

1. 类的定义

  • 类:是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物;如:人类
  • 实例对象:是一类事物的具体体现。对象是类的一个实例(对象并不是找个女朋友),必然具备该类事物的属性和行为;如:小红、小明、小南

面向过程和面向对象

  • 面向过程:当需要实现一个功能时,每个步骤都要亲自实现,详细处理每个细节
  • 面向对象:当需要实现一个功能时,不需要关心具体的步骤,而是找一个已经具有该功能的人(或事物)来帮我实现

类定义格式

// 类可以实现对数据的封装,类由成员变量和成员方法组成
class className {
    // 成员变量    成员变量是直接定义在类当中的,在方法外边
    // 成员方法		成员方法不要写static关键字
}

示例:

class Student {
    // 成员变量
    String name;
    int age;

    // 成员方法
    public void getName() {
        System.out.println(this.name);
    }
}

1.1 对象的使用

通常类不能直接使用,需要根据类创建一个对象来使用,使用步骤:

  • 导包:import 包名称.类名称
  • 创建对象:类名称 对象名 = new 类名称(),如:Student s1 = new Student();
  • 使用
    • 使用成员变量:对象名.成员变量名
    • 使用成员方法:对象名.成员方法名(参数)
// 实例化一个对象
类名 对象名 = new 类名();

对象名.成员变量;
对象名.成员方法()

示例:

public class ClassTest {
    public static void main(String[] args) {
        Student s1 = new Student();
        System.out.println(s1.getName());

        // 设置年龄
        s1.setAge(18);
        System.out.println(s1.getAge());
    }
}

class Student {
    // 成员变量
    String name = "rose";
    int age;

    // 成员方法
    public String getName() {
        return this.name;
    }

    // 设置年龄
    public void setAge(int age) {
        this.age = age;
    }

    // 获取年龄
    public int getAge() {
        return this.age;
    }
}

1.2 成员变量

若成员变量没有进行赋值,那么将会有一个默认值:

数据类型默认值
基本类型整数(byte,short,int,long0
浮点数(float,double0.0
字符(char'\u0000'
布尔(booleanfalse
引用类型数组类,接口null

一个类也可以定义多个成员变量和方法,有 public、private 之分:

  • public:类外部可以访问
  • private:私有,类外部不可访问,格式:private 数据类型 变量名;
    • 权限修饰符,代表最小权限
    • 可以修饰成员变量和成员方法
    • 被修饰后的成员变量和成员方法,只能在本类中才能访问
public class ClassTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = "rose";
    }
}

class Person {
    public String name;
    public int age;
}

以上成员变量 name、age 是公共的,类外部可以访问,这就破坏了类的封装性,导致类外部可以修改,正确的写法应该是:

class Person {
    // 当外部修改成员变量值的时候,会编译报错 p1.name = "rose";
    private String name;
    private int age;
}

1.3 成员变量和局部变量

  • 成员变量
    • 位置:在方法外部,直接写在类当中
    • 作用范围:整个类全都可以通用
    • 默认值:有默认值
    • 内存位置:位于堆内存
    • 生命周期:随着对象创建而诞生,随着对象被垃圾回收而消失
  • 成员变量
    • 位置:在方法内部
    • 作用范围:只有方法当中才可以使用,出了方法就不能再用
    • 默认值:无默认值
    • 内存位置:位于栈内存
    • 生命周期:随着方法进栈而诞生,随着方法出栈而消失

示例:

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

    public void setName(String name) {
        String gender = "男";	// 局部变量
        this.name = name;
    }

2. 方法

2.1 private 修饰符

在类外部可以通过对象来修改成员变量,但是却无法阻止不合理的数据,比如:age 有可能被设置为负数,解决方案:

  • private 关键字修饰要修改的成员变量, 被修饰后的成员变量和成员方法,只能在本类中才能访问
  • 再通过 Getter/Setter 方法实现外部也可以访问和修改成员变量,同时也可以校验数据的合理性
  • 那么可以通过 private 关键字和 Getter/Setter 方法来实现间接修改,这样也可以在 Getter/Setter 方法中校验数据的合理性
public class ClassTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.setName("rose");
        System.out.println(p1.getName());

    }
}

class Person {
    private String name;
    private int age;
	private boolean male; // bool 类型成员变量
    
    // 设置名字
    public void setName(String name) {
        this.name = name;
    }

    // 访问名字
    public String getName() {
        return this.name;
    }
    
    public void setMale(boolean b) {
        male = b;
    }
	
    // bool 类型 Getter 方式是 isXXX()
    public boolean isMale() {
        return male;
    }
}

注意:bool 类型 Getter 方式是 isXXX(),而非 Getter()

2.2 方法定义

语法格式:

修饰符 方法返回类型 方法名(方法参数列表) {
    若干方法语句;
    return 方法返回值;
}
  • 修饰符:public、private

  • 方法返回类型:String、int、void

注意:若没有返回值,可设置返回类型为 void,可省略 return

2.3 private 方法和 this 变量

public 方法就有 private 方法,同理它不允许外部调用,只能在类内部调用:

// private 方法
private int calcAge(int currentYear) {
    return currentYear - this.age;
}

this 变量

this 代表所在类的当前对象的引用(地址值),即对象自己的引用,可解决成员变量和局部变量、参数的命名冲突,如:成员变量和局部变量名字一致

使用格式:

this.成员变量

示例:

// 成员变量和 setName 的参数名冲突,this.name 表示调用成员变量 name
class Person {
    private String name;
    
    // 设置名字
    public void setName(String name) {
        this.name = name;
    }

    // 访问名字
    public String getName() {
        return this.name;
    }
}

若没有命名冲突可省略 this,但是最好是显示地写上。

注意 :方法被哪个对象调用,方法中的 this 就代表那个对象。即谁在调用,this 就代表谁。

2.4 方法参数

方法可以接收 0 个或任意个参数,定义参数时需要数据类型,传递参数必须严格按照参数数据类型传递:

class Person {
    public String name;
    public int age;

    // 执行需传入的参数必须为 String 类型
    public void setName(String name) {
        this.name = name;
    }

    // 无参数
    public String getName() {
        return this.name;
    }
}

// 参数传递
Person p1 = new Person();
p1.setName("rose");

可变参数

当传入的参数不固定或不确定数目时,可使用可变参数:

// 格式  类型...
class Person {
    public String[] names;
	
    // 接收的是一个 String 数组
    public void setName(String... names) {
        this.names = names;
    }
}

// 参数传递
Person p1 = new Person();
p1.setName();
p1.setName("rose");
p1.setName("rose", "lila");

2.5 参数绑定

  • 基本类型参数的传递:是调用方值的复制。双方各自的后续修改,互不影响
  • 引用类型参数的传递:调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方
  • 注意String的值是不可变的 ,对 String 重新赋值的时候,会重新创建一个变量的引用;

2.5.1 基本类型参数传递

public class ClassTest {
    public static void main(String[] args) {
        Person p1 = new Person();
        int n = 20;
        p1.setAge(n);
        System.out.println(p1.getAge());    // 20
        n = 18;
        System.out.println(p1.getAge());    // 20
    }
}

class Person {
    private int age;

    public int getAge() {
        return this.age;
    }

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

修改外部的局部变量n,不影响实例page字段,原因是setAge()方法获得的参数,复制了n的值,因此,p.age和局部变量n互不影响。

2.5.2 引用类型参数传递

public class ClassTest {
    public static void main(String[] args) {
//        Person p1 = new Person();
//        int n = 20;
//        p1.setAge(n);
//        System.out.println(p1.getAge());    // 20
//        n = 18;
//        System.out.println(p1.getAge());    // 20

        Person p2 = new Person();
        String[] full_name = {"li", "xiaoer"};
        p2.setName(full_name);
        System.out.println(p2.getName());   // li xiaoer
        full_name[1] = "da";
        System.out.println(p2.getName());   // li da
    }   
}

class Person {
    private int age;
    private String[] names;

    public int getAge() {
        return this.age;
    }

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

    public String getName() {
        return this.names[0] + " " + this.names[1];
    }

    public void setName(String[] names) {
        this.names = names;
    }

}

数组 full_name 第 1 个元素修改,getName() 方法获取的 names 也跟着改变,这是因为两者指向的是同一变量,其内存地址是同一个。

2.5.3 引用类型之 String 类型参数传递(绑定)

public class ClassTest {
    public static void main(String[] args) {
        Person p2 = new Person();
        String n1 = "rose";
        p2.setName(n1);
        System.out.println(p2.getName());   // rose
        n1 = "lila";
        System.out.println(p2.getName());   // rose
    }   
}

class Person {
    private int age;
    private String name;

    public int getAge() {
        return this.age;
    }

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

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

上面说引用类型的参数传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方;但是 String 类型是个特例。

**String的值是不可变的 ,对String 重新赋值的时候,会重新创建一个新的变量的引用;**所有当变量 n1 = "lila"; 时,它会创建一个新的变量的引用,而 setName() 方法时获取的原先的变量引用,所以修改不会改变。

3. 构造方法

构造方法:可以实现在创建实例的时候,初始化实例字段,特性:

  • 构造方法名称即为类名,无返回值,无 void

  • 调用构造方法,必须用 new 操作符

  • 可以有多个构造方法(有参数、无参数、不同参数),若没有定义构造方法,编译器会自动为我们生成一个默认构造方法,它没有参数,也没有执行语句

public class StructMethod {
    public static void main(String[] args) {
        Person1 p = new Person1("rose", 18);
        System.out.println(p.getAge());
        System.out.println(p.getName());

        Person1 p2 = new Person1("lila");
        Person1 p3 = new Person1();
    }
}

class Person1 {
    private String name;
    private int age;

    // 默认构造方法
    public Person1() {

    }

    // 自定义构造方法 1
    public Person1(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 自定义构造方法 2
    public Person1(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

多个构造方法调用:

Person1 p = new Person1("rose", 18);
Person1 p2 = new Person1("lila");
Person1 p3 = new Person1();

一个构造方法调用另一个构造方法:

this("john", 19);	// 便于代码复用

4. 方法重载

Java 类中可以定义多个名称相同的方法,若只是参数不同,功能类似,那么可以将这类方法称为同名方法,也可以叫做 方法重载,一般而言这类方法返回类型应该相同

class Book {
    public void hello() {
        System.out.println("Hello World!");
    }

    public void hello(String name) {
        System.out.println("Hello " + name);
    }

    public void hello(String name, int age) {
        System.out.println("Hello " + name + "You're age " + age);
    }
}

方法重载的目的是,功能类似的方法使用同一名字,更容易记住,调用起来更简单,如 String类提供了多个重载方法indexOf()

5. Java 对象内存图

【JavaSE】Java面向对象的思想(类、对象、对象调用内存图)

一个 Java 对象的创建 --> 使用在内存中总共大概会开辟三块内存区域:栈内存Stack、堆内存Heap、方法区Method Area

  • 方法调用的时候,该方法所需的内存空间在栈内存中分配,这个过程叫 压栈,方法结束后,该方法所属的内存空间释放,成为 出栈
  • 栈中主要存储的是方法体当中的局部变量
  • 方法的代码段以及整个类的代码段都被存储到方法区内存当中,在类加载的时候这些代码片会载入
  • 程序执行 new 创建对象时,存储在 堆内存 当中,对象内部的实例变量

1、只有一个对象的内存图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yp5t6p8l-1673275268929)(http://img.midworld.top/img/01-只有一个对象的内存图.png)]

  • 方法区:总共有两个类 Phone、Demo1PhoneOne,方法有:main、call、send
  • 栈内存:当执行主函数时,会在栈内存开辟一块空间;当使用对象去修改或访问成员变量时,会直接在堆内存中找到成员变量进行修改,而当调用成员方法时,通过堆内存中的成员方法内存地址找到相应的成员方法,此时成员方法会从方法区进入栈空间(压栈),执行完毕后,就立马出栈
  • 堆内存:当 new 创建对象时,会在堆内存开辟一块空间

2、两个对象使用同一个方法的内存图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oAaANtDA-1673275268930)(http://img.midworld.top/img/02-两个对象使用同一个方法的内存图.png)]

创建两个对象情况和一个对象类似:

  • 创建第二个对象是在堆内存中新建一个对象new Phone();赋给第二个对象名two的地址也是一个新的地址值
  • 对象访问成员变量,访问的是该对象自己的成员变量。
  • 两个对象使用同一个方法,会根据地址值指向同一个方法。因为两个对象中的成员方法,保存的都是方法区中Phone.class中对应成员方法的地址值
  • 两个对象访问成员变量,调用成员方法不会产生任何关联

3、两个引用指向同一个对象的内存图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CpKGyj4g-1673275268932)(http://img.midworld.top/img/03-两个引用指向同一个对象的内存图.png)]

  • Phone two =one; 是将one中保存的对象地址值赋给的twotwo也指向了该对象。

  • 根据onetwo的地址值都可以访问到该同一对象的成员变量、成员方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风老魔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值