Java系列类和对象中需要注意的事情

Posted 波风张三

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java系列类和对象中需要注意的事情相关的知识,希望对你有一定的参考价值。


前言

类和对象是面向对象编程语言的重要概念。Java是一种面向对象的语言,所以要想熟练使用Java,就一定要掌握类和对象的使用。


一、类和对象的初步认识

1.1.类

【类的概念】

将具有相同属性及相同行为的一组对象称为类(class)。

广义地讲,具有共同性质的事物的集合就称为类。

在面对对象程序设计中,类是一个独立的单位,它有一个类名,其内部包含成员变量,用于描述对象的属性;还包括类的成员方法,用于描述对象的行为。

如下:


    class Person{
        String name;//变量
        int age;//变量
        void talk(){//操作数据的方法
            System.out.println("我是:"+name+",今年:"+age+"岁");
        }
}

1.2.对象

【概念】

对象(object)是类的实例化后的产物

一个对象由一组属性和一系列对属性进行操作的方法构成。

在Java中,一切皆为对象。

1.3.类和对象的关系

类是对某一类事物的描述,是抽象的、概念上的定义;
对象是实际存在在该类事物的个体。也可称为实例。

举个例子:
我们需要图纸来造出椅子,这个图纸就是“类”,而由图纸设计出来的椅子就称为“对象”。

类是对象的模板,对象是类的实例。一个类可以对应多个对象。

二、 类和类的实例化

声明一个类就是创建一个新的数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。我们来
看以下简单的声明一个类。

【基本语法】

// 创建类
[标识符]class 类名称{  
    field;//成员属性
    method;//成员方法
}
// 实例化对象
类名称 <对象名> = new 类名称();

标识符可以是public、private、protected。class为定义类的关键字,{}中为类的主体。
类中的元素称为:成员属性。类中的函数称为:成员方法。

类的定义:

class Person {
    public int age;//成员属性 实例变量
    public String name;//定义人的姓名
    public String sex;//性别
    public void eat() {//成员方法
       System.out.println("吃饭!");  
   }
    public void sleep() {//成员方法
       System.out.println("睡觉!");  
   }
}

【注意】这里在定义方法是没有使用到static关键字。后面我们会详细介绍static关键字。

类的实例化:

class Person {
    public int age;//成员属性 实例变量
    public String name;
    public String sex;
     public void eat() {//成员方法
       System.out.println("吃饭!");  
   }
    public void sleep() {
       System.out.println("睡觉!");  
   }
}
public class TestDemo{
 public static void main(String[] args) {
        Person person = new Person();//通过new实例化对象
        person.eat();//成员方法调用需要通过对象的引用调用
        person.sleep();
        //产生对象     实例化对象
        Person person2 = new Person();//可创建多个对象
        Person person3 = new Person();
 }
}

对象实例化的过程如下图:

【结论】

  1. new 关键字用于创建一个对象的实例
  2. 使用 . 来访问对象中的属性和方法
  3. 同一个类可以创建对个实例

三、static关键字

1.使用static定义属性

在程序中用static定义属性的化,则此变量称为静态属性。

那什么是静态属性?使用静态属性又有什么好处呢?

看下面代码:


class Person{//定义Person类,有3个属性,name,age,city
    String name;
    String city;
    int age;
    public Person(String name,String city,int age){//定义构造方法
        this.name=name;
        this.city=city;
        this.age=age;
    }
    public String talk(){//定义talk方法
        return "我是:"+this.name+",今年:"+this.age+"岁,来自:"+this.city;
    }
}

public class TestDemo{
    public static void main(String[] args) {
        Person p1=new Person("张三","中国",25);//实例化Person对象
        Person p2=new Person("李四","中国",25);
        Person p3=new Person("王五","中国",25);
        System.out.println(p1.talk());//调用talk()方法输出信息
        System.out.println(p2.talk());
        System.out.println(p3.talk());
    }

}

观察发现,所有的Person对象都有一个city属性,而且所有属性都相同,为中国。

如果我们程序中有100个Person对象,想要改变city属性,是不是要调用100次,这就太麻烦了。

所以我们可以用static关键字来解决这个问题,用它来修饰类的属性后,则此属性就是共同属性了。
修改如下:

class Person{//定义Person类,有3个属性,name,age,city
    String name;
    static String city;//static修饰
    int age;
    public Person(String name,String city,int age){//定义构造方法
        this.name=name;
        this.city=city;
        this.age=age;
    }
    public String talk(){//定义talk方法
        return "我是:"+this.name+",今年:"+this.age+"岁,来自:"+this.city;
    }
}

public class TestDemo{
    public static void main(String[] args) {
        Person p1=new Person("张三","中国",25);//实例化Person对象
        Person p2=new Person("李四","中国",25);
        Person p3=new Person("王五","中国",25);
        System.out.println("修改前的信息"+p1.talk());//调用talk()方法输出信息
        System.out.println("修改前的信息"+p2.talk());
        System.out.println("修改前的信息"+p3.talk());
        System.out.println("=================================");
        p1.city="美国";
        System.out.println("修改后的信息"+p1.talk());//调用talk()方法输出信息
        System.out.println("修改后的信息"+p2.talk());
        System.out.println("修改后的信息"+p3.talk());
    }

}


【总结】

static修饰的属性中,同一个类的不同实例共用同一个静态属性.

2.使用static定义方法

如果在任何方法上应用 static 关键字,此方法称为静态方法

  1. 静态方法属于类,而不属于类的对象
  2. 可以直接调用静态方法,而无需创建类的实例
  3. 静态方法可以访问静态数据成员,并可以更改静态数据成员的值。

例子如下:

class Person{//定义Person类,有3个属性,name,age,city
    String name;
    static String city;//定义静态属性city
    int age;
    public Person(String name,String city,int age){//声明一个构造方法
        this.name=name;
        this.city=city;
        this.age=age;
    }
    public String talk(){//定义talk方法
        return "我是:"+this.name+",今年:"+this.age+"岁,来自:"+this.city;
    }
    public static void setCity(String c){//声明一个静态方法
    city.c;
    }
}

public class TestDemo{
    public static void main(String[] args) {
        Person p1=new Person("张三","中国",25);//实例化Person对象
        Person p2=new Person("李四","中国",25);
        Person p3=new Person("王五","中国",25);
        System.out.println("修改前的信息"+p1.talk());//调用talk()方法输出信息
        System.out.println("修改前的信息"+p2.talk());
        System.out.println("修改前的信息"+p3.talk());
        System.out.println("=================================");
        p1.city="美国";
        System.out.println("修改后的信息"+p1.talk());//调用talk()方法输出信息
        System.out.println("修改后的信息"+p2.talk());
        System.out.println("修改后的信息"+p3.talk());
    }

}
【注意】
静态方法和实例无关, 而是和类相关. 因此这导致了两个情况
  1. 静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的)
  2. this和super两个关键字不能在静态上下文中使用(this 是当前实例的引用, super是当前实例父类实例的引用, 也
    是和当前实例相关).

此外:

  • 我们曾经写的方法为了简单, 都统一加上了 static. 但实际上一个方法具体要不要带 static, 都需要是情形而定.
  • main 方法为 static 方法.

四、 封装

1.封装的含义

封装是什么?

封装是将描述某类事物的数据与处理这些数据的函数封装在一起,形成一个整体,称为类。

一旦设计好类,就可以实例化该类的对象。我们在形成一个对象的同时也界定了对象与外界的内外界限。

对象的属性、行为等实现的细节则被分装在对象的内部。外部使用者和其他对象只能经由原先规划好的接口与对象交互。

封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.

这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度

2.private实现封装

private/ public 这两个关键字表示 “访问权限控制” .

  • 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.

  • 被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用.

换句话说, 类的使用者根本不需要知道, 也不需要关注一个类都有哪些 private 的成员. 从而让类调用者以更低的成本来使用类。

以一只猫的例子来举例:

class Mycat{
    public float weight; //通过public修饰符,开放MyCat的属性给外界
    Mycat(){}
}

class TestDemo{
    public static void main(String[] args) {
        Mycat aCat=new Mycat();
        aCat.weight=-10.0f;   //设置Mycat的属性值
        float tmp=aCat.weight;//获取Mycat的属性值

        System.out.println("这只猫的体重是:"+tmp);
    }
}



如果这里将类中的属性用private封装,就能避免这种错误的发生了。
修改如下:


这里有一个问题,如果我们非要给对象的属性赋值呢?我们能不能做到,或者说有没有什么方法让我们达到这个目的?

这里就需要用到Setter和Getter方法了。

3.Setter和Getter方法

通常

  1. 对属性设置的方法被命名为SetXxx(),其中Xxx为任何有意义的名称,这类方法可统称为Setter方法。
  2. 对取属性值的方法被命名为GetYyy,其中Yyy为任何有意义的名称,这类方法可统称为Getter方法。

我们下面尝试用这两个方法修改猫的体重:

class Mycat{
    private float weight; //通过private修饰符,开放MyCat的属性给外界
    public void SetWeight(float wt){
        if(wt>0){
            this.weight=wt; 
        }else {
            System.out.println("weight设置非法(应该>0)");
            weight=10.0f;
        }
    }
    public float GetWeight(){
        return weight;
    }
}

class TestDemo{
    public static void main(String[] args) {
        Mycat aCat=new Mycat();
        aCat.SetWeight(-10f);   //设置Mycat的属性值
        float tmp=aCat.GetWeight();//获取Mycat的属性值

        System.out.println("这只猫的体重是:"+tmp);
    }
}


【注意】

  1. getName 即为 getter 方法, 表示获取这个成员的值.
  2. setName 即为 setter 方法, 表示设置这个成员的值.
  3. 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例的引用
  4. 不是所有的字段都一定要提供 setter / getter 方法, 而是要根据实际情况决定提供哪种方法
  5. 在 IDEA 中可以使用 alt + insert (或者 alt + F12) 快速生成 setter / getter 方法. 在 VSCode 中可以使用鼠标右键菜单 -> 源代码操作 中自动生成 setter / getter 方法.

五、构造方法

构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作。

声明对象并实例化的格式:

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

  1. 类名称:表示要定义变量的类型,只是有了类之后,变量的类型是有用于自己定义的。
  2. 对象名称:表示变量的名称,变量的命名规范与方法相同。
  3. new:是作为开辟堆内存的唯一方法,表示实例化对象。
  4. 类名称():这就是一个构造方法。

所谓构造方法,就是在每一个类中定义的,并且实在使用关键字new实例化一个新对象的时候默认调用的方法。

class Person { 
 
 private String name;//实例成员变量
 private int age; 
 private String sex; 
 //默认构造函数 构造对象 
 public Person() { 
 this.name = "caocao"; 
 this.age = 10; 
 this.sex = "男"; 
 } 
 //带有3个参数的构造函数
 public Person(String name,int age,String sex) { 
 this.name = name; 
 this.age = age; 
 this.sex = sex;} 
 public void show(){ 
 System.out.println("name: "+name+" age: "+age+" sex: "+sex); 
 } 
 
} 
public class Main{ 
 public static void main(String[] args) { 
 Person p1 = new Person();//调用不带参数的构造函数 如果程序没有提供会调用不带参数的构造函数
 p1.show(); 
 Person p2 = new Person("zhangfei",80,"男");//调用带有3个参数的构造函数
 p2.show(); 
 } 
} 
// 执行结果
name: caocao age: 10 sex: 男
name: zhangfei age: 80 sex:

使用构造方法需要注意以下几点:

  • 方法名称必须与类名称相同
  • 构造方法没有返回值类型声明
  • 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
  • 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
  • 若类中定义了构造方法,则默认的无参构造将不再生成
  • 构造方法支持重载. 规则和普通方法的重载一致
  • 构造方法不能被static和final修饰

六、this关键字

使用this关键字,只需遵循一个原则,就是this表示当前对象,而所谓的当前对象就是指调用类中方法或属性的那个对象。


【注意】

  1. this.data; 表示调用当前对象的属性
  2. this.func(); 表示调用当前对象的方法
  3. this(); 表示调用当前对象的其他构造方法

七、代码块

代码块用{ }将多行代码封装在一起,形成一个独立的代码区域。
格式如下:

{
//代码块
}

代码块有四种:

  1. 普通代码
  2. 构造代码块
  3. 静态代码块
  4. 同步代码块

代码块不能独立运行,需要依赖于其他配置

1.普通代码块

普通代码块是最常见的代码块,它不能单独存在于类中,需要紧跟在方法名后面,并通过方法调用。

public class Main{ 
 public static void main(String[] args) { 
 { //直接使用{}定义,普通方法块
 int x = 10 ; 
 System.out.println("x1 = " +x); 
 } 
 int x = 100 ; 
 System.out.println("x2 = " +x); 
 } 
}

2.构造代码块

构造代码块就是在类中直接定义的,且没有任何前缀,后缀以及修饰符的代码块。
前面提到,在一个类中,至少需要有一个构造方法,如果没有,编译器就会“隐式”地配备一个。

 private String name;//实例成员变量
 private int age; 
 private String sex; 
 
 public Person() { 
 System.out.println("I am Person init()!"); 

以上是关于Java系列类和对象中需要注意的事情的主要内容,如果未能解决你的问题,请参考以下文章

Scala 系列—— 类和对象

Java入门系列-14-深入类和对象

Java基础系列--05_面向对象

初始Java 来自Java SE的第六节课 类和对象

JAVA零基础入门系列Day11 Java中的类和对象

JAVA方法的定义