Java 类和对象

在面向对象语言中万物皆对象,一切都围绕对象来进行,找对象、建对象,用对象等。

  • 类:把具有相同特征和行为的一组对象抽象为类,类是抽象概念,如人类、车类等,无法具体到每个实体。

  • 对象:某个类的一个实体,当有了对象后,这些特征便有了相应的值,行为也就有了相应的意义。

类是描述某一对象的统称,对象是这个类的一个实例而已。有类之后就能根据这个类来产生具体的对象。一类对象所具备的共同特征和行为(方法)都在类中定义。

Java 类和对象_第1张图片

Java 中的类

类可以看成是创建对象的模板。

Java 类和对象_第2张图片

从上图中可以看出,类是很多具体实体的共同特征,例如三只犬,都有共同的品种、大小、颜色和年龄等特征,也有吃饭、睡觉、跑和姓名的行为。只不过它们的值不一样而已。

定义一个类

public class 类名{
    // 属性
    
    // 方法
}

定义一个类时,可以在类里设置两种类型的元素:属性方法

属性

属性是对一个类的描述,属性的值是这个类中不同对象的区分。

属性是直接定义在类中的变量,它还有一个名字叫做成员变量,它的定义和“普通变量”的定义基本一致。

[修饰符] 属性类型 属性名 [ = 默认值];

修饰符:可以省略,可以是 publicprotectedprivatestaticfinal等,也可以相互组合起来修饰属性。

属性类型:可以是 Java 语言允许的任何数据类型,包括基本数据类型引用数据类型

属性名:和普通变量的命名原则一致,但若可读性角度来说:属性名应该是由一个或多个有意义的单词连缀而成,第一个单词首字母小写,后面每个单词首字母大写,其他字母全部小写,单词与单词之间不需使用任何分隔符。

默认值:定义属性还可以定义一个默认值,如果未赋值,系统会赋予合适的初值。基本数据类型是 0,引用数据类型是 null

public class Person{
    private int id;
    public String name;
    char gender;
}

方法

Java 类和对象_第3张图片

修饰符:可以省略,也可以是 publicprotectedprivatestaticfinalabstract等, 其中 publicprotectedprivate 三个最多只能出现一个,abstractfinal 最多只能出现其中之一,它们可以与 static 组合起来修饰属性。

方法返回值类型:返回值类型可以是 Java 语言允许的任何数据类型,包括基本类型和引用类型。若声明了返回值类型,则方法体内必须有一个有效的 return 语句,该语句返回一个变量或一个表达式(变量或表达式类型必须与此处声明的类型匹配)。若方法没有返回值,必须使用 void 来声明。

方法名:与属性名规则基本相同,通常建议方法名以英文字的动词开头。

形参列表:用于定义该方法可以接受的参数,由零组或多组“参数类型 形参名”组合而成,多组参数之间以英文逗号(,)隔开,形参类型和形参名之间英文空格隔开。

注意:方法体里多条可执行性语句之间有严格的执行顺序,排在方法体前面的语句总是先执行,排在方法体后面的语句总是后执行。

public class Student{
    private String name;
    private int age = 33;
    
    public int getAge(){
        System.out.println("获取当前对象的年龄");
        return age;
    }
    
    public void readBook(String bookName){
        System.out.println(name + "正在读:" + bookName);
    }
}

文件和类

刚才在定义类时,我们会创建一个 .java 结尾的源文件,类的名称和源文件的名称一致。那么定义的类和源文件有什么关系么?

一个源文件中只能有一个 public 类,源文件的名称应该和 public 类的类名保持一致。一个源文件可以有多个非 public 类。

如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。

如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。

import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

Java 中的对象

现在让我们深入了解什么是对象。看看周围真实的世界,会发现身边有很多对象,车,狗,人等等。

所有这些对象都有自己的状态和行为。

拿一条狗来举例,它的状态有:名字、品种、颜色,行为有:叫、摇尾巴和跑。对比现实对象和软件对象,它们之间十分相似。

软件对象也有状态和行为,软件对象的状态就是属性,行为通过方法体现。

在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

创建具体的对象

对象是根据类来创建的。在 Java 语言中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:

  1. 声明:声明一个对象,包括对象名称和对象类型。

  2. 实例化:使用关键字 new 来创建一个对象。

  3. 初始化:使用 new 创建对象时,会调用构造方法初始化对象。

创建对象使用一个关键字 new 来完成。创建对象的语法如下:

类名称 对象名 = new 类名称();

产生了一个类的具体实现,我们把它称之为对象,这个产生的对象其实就是一个变量,这个变量的数据类型就是这个类。所以,我们类就是我们自定义的一个数据类型,而这个类所产生的对象,都是这个类型的变量。例如:

int a = 9;
String b = "Hello,GuanWei";
Person person = new Person();

调用属性

我们刚才学习了怎么在类中定义属性,那么很多同学都在想,这个属性定义好后如何使用?

对于属性的调用我们分为两种情况:

  • 本类调用

  • 它类调用

本类调用

在本类中的方法内,可以直接调用本类定义的属性,无需额外操作。

public class Person{
    int id = 1;
    String name;
    public void show(){
        name = "张三";
        System.out.println("我是:" + name + ",编号:" + id);
    }
}
它类调用

其他类需要通过刚产生出来的对象来使用这些属性。

person.id = 1;
String name = person.name;

我们可以通过 对象名.属性 的方式来操纵它。对于属性而言:

  • 获取属性的值

  • 设置属性的值

调用方法

和调用属性相似的是,调用方法也有如下的几种情况:

  • 本类调用

  • 它类调用

  • 递归

Java 类和对象_第4张图片

本类调用

在本类中的方法内,可以直接调用本类定义的其他,无需额外操作。

public class Person{
    
    public void eat(){
        String name = getName();
        System.out.println(name + "准备吃饭!");
    }
    
    public String getName(){
        return "张三";
    }
}
它类调用

其他类需要通过产生出来的对象来使用这些方法。

person.eat();
String name = person.getName();
递归调用

递归调用是一种特殊的嵌套调用,是某个方法调用自己或者是调用其他方法后再次调用自己的,只要方法之间互相调用能产生循环的则一定是递归调用。

public class Person{
    
    public void eat(){
        String name = getName();
        System.out.println(name + "准备吃饭!");
        // 递归调用
        eat();
    }
    
    public String getName(){
        return "张三";
    }
}
形参列表和实参列表
  • 形式参数列表:在声明方法时的参数列表,即形参列表,声明调用该方法时需要传递什么类型的数据。

  • 实际参数列表:在调用方法时,需要实际传给方法的数据,即实参列表。按照方法的形参列表的要求传递给方法一系列具体数据。

public class Count{
    // 形式参数列表
    public void sum(int a,int b){
        System.out.println(a + "+" + b + "=" + (a + b));
    }
    public void show(){
        int num1 = 23;
        int num2 = 21;
        // 实际参数列表
        sum(num1,num2);
    }
}

构造方法

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

定义

  • 方法名称与类名称完全相同。

  • 构造方法没有返回值声明(不是void)。

  • 一个类中至少存在一个构造方法,若没有显示定义,编译器会生成一个默认的无参构造。

public class Person{
    // 构造方法
    public Person(){
        // 构造方法的实现
    }
    public Person(int a){
        // 构造方法的实现
    }
    public Person(int a,String b){
        // 构造方法的实现
    }
    public Person(String a){
        // 构造方法的实现
    }
    // ....
}

分类

  • 显式构造器

    • 无参数构造器

    • 有参数构造器

  • 隐式构造器

隐式构造器

当一个类中没有提供任何构造方法,系统默认提供一个无参数的构造方法。这个无参数的构造方法叫做隐式构造器,也叫做缺省构造器。

显式构造器

显式构造器就是程序员自己书写的构造器,这些构造器的名称必须和类名一致。通过形式参数列表的不同来区分这些构造器。

作用

构造方法的作用只有一个:初始化对象,会在产生对象时,给对象未赋值的属性赋值。

调用

使用 new 运算符来调用构造方法。从这里我们可以看到,构造器会在产生对象时被调用。

new 构造方法名(实际参数列表);
给属性赋值
public class Person{
    int id;
    String name;
    char gender;
    public Person(){
        id = 1;
        name = "张三";
        gender = '男';
    }
    public Person(int id1,String name1,char gender1){
        id = id1;
        name = name1;
        gender = gender1;
    }
}
// 其他类的main方法
// 调用了 Person 类的无参数构造器给属性赋值
Person p1 = new Person();
// 调用了 Person 类的有参数构造器给属性赋值
Person p2 = new Person(3,"关为",'男');
this 关键字
public class Person{
    int id;
    String name;
    char gender;
    public Person(){
        id = 1;
        name = "张三";
        gender = '男';
    }
    // ❌的写法
    public Person(int id,String name,char gender){
        // 这里定义的形式参数id、name和gender和成员变量重名了,如果还是这样赋值是错误的
        id = id; // ❌
        name = name; // ❌
        gender = gender; // ❌
    }
    // ✔的写法
    public Person(int id,String name,char gender){
        // 这里我们要使用到 this 关键字,
        this.id = id; // 将参数id值赋予成员变量id
        this.name = name; 
        this.gender = gender; 
    }
}

this 关键字表示对当前对象的引用,一般在重名时使用。

隐式构造器

隐式构造器会给未赋值的属性赋予合适的初值(原始类型都是 0,引用类型是 null)。

public class Person{
    int id;
    String name;
    char gender;
    public void show(){
        System.out.println("id:" + id);
        System.out.println("name:" + name);
        System.out.println("gender:" + gender);
    }
}
// 其他类的main方法
Person person = new Person();
person.show();

输出的结果是:

Java 类和对象_第5张图片

显式构造器

当我们书写了显式构造器后,系统的无参数隐式构造器就无法被程序员调用了。

public class Person{
    int id;
    String name;
    char gender;
    public Person(int id){
        // ...
    }
}
// 其他类的main方法
Person person = new Person(); // ❌ 没有定义无参数构造器

Java 类和对象_第6张图片

构造器未赋值

如果我们自己定义的构造器并没有给所有属性赋值,那么这些属性的值是什么呢?

public class Person{
    int id;
    String name;
    char gender;
    public Person(int id){
        this.id = id;
    }
    public void show(){
        System.out.println("id:" + id);
        System.out.println("name:" + name);
        System.out.println("gender:" + gender);
    }
}
// 其他类的main方法
Person person = new Person(2);
person.show();

Java 类和对象_第7张图片

我们可以看到的是,id 属性的值是我们填充的,其他属性的值仍然是系统默认初值。也就是说,未赋值的属性,即使我们的构造器也没有赋值,系统仍然会赋予合适的初值。

成员变量和局部变量

变量声明的位置决定了变量的作用域,变量作用域确定了可在程序中按变量名访问该变量的区域。

Java 类和对象_第8张图片

成员变量

类中直接定义的变量成为成员变量。 对于成员变量也有叫作实例变量instance variable)。这里通常指非 static 进行修饰的变量。

public class Person{
    private int id ;
    private String name ;
}

需要注意的是, 成员变量最好使用私有修饰符, 进行权限的控制, 保证成员属性不往外暴漏属性值。 而是给一个行为或者动作去触发修改属性。

局部变量

局部变量分为两种, 一种是方法内的局部变量, 另外一种是代码块中的变量。 不管哪一种,局部变量都只能在当前定义的区域中使用。

public class Person{
    public void eat(){
        String name = "GuanWei";
        for(int i=1;i<11;i++){
            System.out.println(i + ":" + name);
        }
    }
}

区别

作用域不同
  • 局部变量的作用域仅限于定义它的程序体。

  • 成员变量的作用域在整个类内部都是可见的,如果作用域允许,其他类也可以使用。

初始值不同
  • Java 会给成员变量一个初始值。

  • Java 不会给局部变量赋予初始值。

重名问题
  • 在同一个方法中,不允许有同名局部变量;在不同的方法中,可以有同名局部变量。

  • 两类变量同名时,局部变量具有更高的优先级。

  • 可以使用 this 关键字来调用成员变量。

你可能感兴趣的:(Java,基础,java)