JavaSE 类和对象

1 类与对象的初步认知

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

1.1 面向过程

面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。以传统的洗衣服作为例子,面向过程所注重的是洗衣服的过程,少了一个环节可能都不行。具体如下图所示:
在这里插入图片描述
而且不同衣服洗的方式,时间长度,拧干方式都不同,处理起来就比较麻烦。如果将来要洗鞋子,那就是另一种方式。按照该种方式来写代码,将来扩展或者维护起来会比较麻烦。

1.2 面向对象

面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来。面向对象的思想主要分为找对象、创建对象和适用对象三大部分。我们继续以传统的洗衣服作为例子,面相对象就不关注洗衣服的过程,具体洗衣机是怎么来洗衣服,如何来甩干的,用户不用去关心,只需要将衣服放进洗衣机,导入洗衣粉,启动开关即可,通过对象之问的交互来完成的。具体如下图所示:
在这里插入图片描述
这里总共有四个对象:人、衣服,洗衣粉、洗衣机。
整个洗衣服的过程:人将衣服放进洗衣机,倒入洗衣粉,启动洗衣机,洗衣机就会完成洗衣过程,并且甩干。
整个过程主要是:人、衣服、洗衣粉、洗衣机四个对象之间交互完成的,人不需要关心洗衣机具体是如何洗衣服的,是如何甩干的。
同理可知,面向过程: 1.把冰箱打开 2. 把大象放入 3. 冰箱关起来。 面向对象: 打开冰箱,储存,关闭都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中。
以上就是面相对象的思想来处理,而在java中借助面相对象思想来处理问题,首先需要用类来描述对象。

2 类

类就是一类对象的统称,对象就是这一类具体化的一个实例。在IDEA中我们可以通过鼠标右击一个Java项目的src文件去新建一个类,如下图所示就可以通过以下三个步骤创建出 TestDemo2 这个类,具体情况如下图所示:
在这里插入图片描述
在这里插入图片描述
简单的例子:我们人就是一个类,而通过这个模子可以有很多不同的人,那么在这个例子当中,人就是那个模子,而很多不同的人就是那个对象,所以一个个不同的人就是一个实体。一个模子可以实例化无数个对象。
总的来说:类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。
声明一个类就是创建了一个新的数据类型,此时它可以像String、int一样定义变量,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。我们来看以下简单的声明一个类。

2.1 类和类的实例化

声明一个类也就是创建一个类,我们可以使用关键字 class 来声明类。用类创建对象的过程,称为类的实例化。

  1. 类只是一个模型一样的东西,限定了类有哪些成员。
  2. 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。
  3. 做个比方:类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。

创建一个类和实例化一个类的基本语法如下所示:
基本语法:

// 创建类
class 类名 {
field;//成员属性
method;//成员方法
}
// 实例化对象
类名 对象名 = new 类名( );

class为定义类的关键字,{ }中为类的主体。
类中的元素称为:成员属性。类中的函数称为:成员方法。
注意这里和之前写的方法不同, 此处写的方法不带 static 关键字。
具体代码示例如下所示:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量
    public int age;
    public static int count = 10//静态成员变量
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        //Person person;
        Person person = new Person();
    }
}

对于上面的代码,我们有3点内容要说:

  1. 此时这个Person就把它叫做类,也叫做类型;这里的class Person就是自定义了一种类型,而这种类型就叫做Person类型,所以此时你就可以利用Person,像String、int一样定义变量, 就比如此时我们在mian()函数中所定义的Person person。
  2. 一个类由属性和方法组成。属性也叫做成员变量,它分为静态成员变量和实例成员变量;方法也分为静态成员方法和实例成员方法。对于一个人来说,都有他的名字和年龄,就是这里的属性,也把它叫做字段,也把它叫做成员变量;对于一个人来说,都有他的行为,就是Java里的方法,也叫做函数。
  3. main( )函数中的new Person()叫做对象,也就是真正意义上的实体;person叫做引用;new Person()的过程叫做对象的实例化,也称为此时实例化了一个对象。

我们把下图中的public叫做访问修饰限定符,访问修饰限定符有四个,分别为:public、private、protected和默认权限。在est( )这个方法前如果你不加public,直接是 void eat( ) { System.out.println(“吃饭”);},则这里就是默认权限。具体如下图所示:
在这里插入图片描述

此时person是一个引用,也是一个局部变量,所以它被存放在栈上;堆上此时放的是new Person();此时的String name和int age是一个实例成员变量,它们存在对象里面,也就是new Person()里面。此时去访问这个成员变量时,就可以通过对象的引用,即person.name就可以实现对于这个成员变量的访问。可借助下图进行理解:
在这里插入图片描述
但如果我们写下面的这个代码就会出现编译错误,因为局部变量在使用前一定要进行初始化,这里未进行初始化,所以这里会出现编译报错。具体代码如下所示:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量
    public int age;
    public static int count = 10//静态成员变量
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        //Person person;
        Person person = new Person();
        String str;//局部变量在使用前一定要进行初始化
        System.out.println(str);//局部变量在使用前一定要进行初始化,这里未进行初始化,所以这里会出现编译报错
    }
}

但对于这个代码中的 public String name;和public int age;这两句代码来说,我们知道这里的name和age不是局部变量,而是实例成员变量。
实例成员变量它是定义在类的内部,方法的外部的。对于成员变量来说:如果没有初始化,默认就是其对应的0值。

byte short int long其对应的0值都是
对于引用类型(String, Array, 以及自定制类)其对应的0值都是 null
float其对应的0值是0.0f
double其对应的0值是0.0
boolean其对应的0值是false
char其对应的0值是’u0000’

实例成员变量的访问形式是通过对象的引用来访问实例成员变量,如person.name;方法也可以通过引用进行调用,如person.eat();。具体代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量
    public boolean flg;
    public char ch;
    public void eat(){
        System.out.println("吃饭");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        System.out.println(person.age);
        System.out.println(person.flg);
        System.out.println(person.ch);
        person.eat();
        person.sleep();
    }
}

注意:

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

如何访问静态成员变量和静态方法?
这里不需要通过对象的引用来访问,我们只可以直接通过类名进行访问静态成员变量和静态方法,访问的形式就是用符合 . 来进行访问。所以说,有些书也把静态成员变量和成员方法叫做类变量或者类方法。具体代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量
    public boolean flg;
    public char ch;
    public void eat(){
        System.out.println("吃饭");
    }
    public static void sleep(){
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        System.out.println(Person.count);
        Person.sleep();
    }
    }

静态成员方法内部,不可以调用非静态方法,具体代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量
    public boolean flg;
    public char ch;
    public void eat(){
        System.out.println("吃饭");
    }
    public static void sleep(){
        eat();//静态成员方法内部,不可以调用非静态方法,所以这里会出现编译报错
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        System.out.println(Person.count);
        Person.sleep();
    }
    }

一个类可以通过关键字new,实例化多个对象的代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public void eat(){
        System.out.println("吃饭");
    }
    public static void sleep(){
        System.out.println("睡觉");
    }
     public void show(){
        System.out.println("姓名:"+name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "gap";
        person.age = 98;
        Person person1 = new Person();
        person1.name = "gapa";
        person1.age = 18;
        Person person2 = new Person();
        Person person3 = new Person();
        Person person4 = new Person();
    }
}

要注意这个代码可借助下图进行理解,我们每一个对象里都有name、age、flg和ch,但是count只有一份,它是静态成员变量,存放在方法区中。
在这里插入图片描述
方法区里还有方法表,具体如下图所示:
在这里插入图片描述
又如下面这段代码,直接System.out.println(person1);,按理来说其输出结果应该是person1的存储地址,但实际运行结果如下图所示,具体代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println("睡觉");
    }
    public void show(){
        System.out.println("姓名:"+name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "bit";
        person1.age = 10;
        person1.show();
        System.out.println(person1);
    }
    }

实际运行结果如下图所示:
在这里插入图片描述
我们这里@符号后面的一串字符是对象地址的哈希值,@属于一个分割符,@符号前面的一串字符是类名,所以就是说我们用 System.out.println( );直接去打印一个引用的时候,它所打印出来是类名@对象地址的哈希值。因为当用 System.out.println( );打印对象的引用的时候,我们发现其实底层调用的是object的toString方法。
Object是所有类的父亲,但是如果现在你 在你自己的这个类中,重写了一个自己的toString方法,则用 System.out.println( );打印对象的引用的时候,程序会默认调用你自己重写的这个toString方法。快捷键Alt+Insert 选用toString(),点击ok即可自动生成下面这个方法,或者直接鼠标右键选择Generate,选择toString(),点击ok也可自动生成下面这个方法。具体代码示如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println("睡觉");
    }
    //快捷键Alt+Insert 选用toString() 点击ok即可自动生成下面这个方法
    //这里相当于重写了toString()方法
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }

    public void show(){
        System.out.println("姓名:"+name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "bit";
        person1.age = 10;
        person1.show();
        System.out.println(person1);
    }
    }

运行结果如下图所示:
在这里插入图片描述
代码中的@Override是注解,注解有很多种,我们现在看到的只是其中的一种,代表当前方法是重写的方法。@Deprecated这个注解表示当前方法已经过时。
当出现下面代码时,要注意第一种表示person这个引用不引用任何对象,第二种表示person引用了person1引用的对象,具体代码示例如下:

class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println("睡觉");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }

    public void show(){
        System.out.println("姓名:"+name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        //1.person这个引用不引用任何对象
        Person person =null;
        //2.person引用了person1引用的对象
        Person person1 = new Person();
        person = person1;
    }
    }

2.2 类的成员

对于类的成员变量来说,总共有3种方式的初始化:

1. 默认初始化;
2. 就地初始化;
例:class Person{
public String name = “bit”;
public int age = 10;}
3. 类外进行初始化;(但是我们一般不这样用,因为这样导致代码的耦合性太差)
例:public static void main (String[ ] args) {
Person person = new Person();
person.name = “gap”;
person.age = 98;
System.out.println(person);
Person person1 = new Person();
person1.name = “gapa”;
person1.age = 18;
System.out.println(person1);
}

3 static关键字

static关键字可以:

1. 修饰成员变量;
访问形式:类名.静态成员变量进行访问;
内存的存储方式:方法区;
特点:静态的只有一份,且不依赖对象。所以我们也把静态的成员变量叫做类变量。
2. 修饰成员方法;
访问形式:类名.方法名( )进行访问;
特点:在静态方法的内部,是不可以访问实例成员变量的。所以我们也把静态的成员方法叫做类方法;
注意:main( )方法是静态方法。
3.修饰类;
4.修饰代码块。

  1. 关于static关键字修饰成员变量的特点,我们可以通过下面代码中的size和count的运行结果进行体会,注释部分与不注释部分的代码对于count来说表示的是一样的功能,具体代码示例如下:
class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public int size;
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        //注释部分与不注释部分的代码对于count来说表示的是一样的功能
        Person.count++;
        Person.count++;
        Person.count++;
        System.out.println(Person.count);//运行结果:13
        /*Person person1 = new Person();
        person1.size++;
        person1.count++;
        Person person2 = new Person();
        person2.size++;
        person2.count++;
        Person person3 = new Person();
        person3.size++;
        person3.count++;
        System.out.println(person3.size);
        //运行结果:1
        System.out.println(person3.count);
        //运行结果:13
        */
    }
    }
  1. 关于static关键字修饰成员方法的特点,我们可以通过下面代码中的sleep( )方法中的编译报错部分进行体会,具体代码示例如下:
class Person{
    public String name;//把name叫做属性,也把它叫做字段,也把它叫做实例成员变量,String默认的0值就是null
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println(count);//编译通过,可以运行
        System.out.println(age);//编译报错,不可以运行
        System.out.println("睡觉");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person.sleep();
    }
    }
  1. 分析内存布局
    对于下面这段代码来说,Person类当中的age、name、sex、SIZE都是实例成员变量,是对象,存放在堆中;Person类当中的count、COUNT是静态成员变量,放在方法区,且只有一份;main( )函数中的a是局部变量,放在栈上。
    所以,一个变量放在哪里,和final没有关系,只与是否有static有关系
class Person {
    public int age;//实例变量   存放在对象内
    public String name;//实例变量
    public String sex;//实例变量
    public static int count;//类变量也叫静态变量,编译时已经产生,属于类本身,且只有一份。存放在方法区
    public final int SIZE = 10;//被final修饰的叫常量,也属于对象。 被final修饰,后续不可更改
    public static final int  COUNT = 99;//静态的常量,属于类本身,只有一份 被final修饰,后续不可更
}
    public class TestDemo2 {
    public static void main(String[] args) {
    final int a = 10;
    }
    }

4 封装

提问: OOP语言的特征有哪些?
答:OOP是面向对象,所以OOP语言的特征是继承、封装、多态。
封装:

1. 什么是封装?
答:把重要的数据和重要的方法用关键字private进行修饰,修饰之后其权限就变为私有的,也就是只能在类内进行访问。
2. 封装的意义是什么?
答:a.对数据的安全性。 b.类的调用者,对类的使用成本降低了。

this到底代表啥
答:this代表当前对象的引用,但是有些书或者资料经常说this代表当前的对象,这句话是错误的。要习惯使用this关键字。

4.1 用private实现封装

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

  1. 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用。
  2. 被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用。换句话说, 类的使用者根本不需要知道, 也不需要关注一个类都有哪些 private 的成员,从而让类调用者以更低的成本来使用类。

直接使用 public:
具体代码示例如下:

class Person{
    public String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;

    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println(count);//编译通过,可以运行
        //System.out.println(age);编译报错,不可以运行
        System.out.println("睡觉");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }

    public void show(){
        System.out.println("姓名:"+ name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "bit";
        person1.age = 10;
        System.out.println(person1);
    }
    }

这样的代码导致类的使用者(main方法的代码)必须要了解 Person 类内部的实现, 才能够使用这个类,学习成本较高;一旦类的实现者修改了代码(例如把 name 改成 myName), 那么类的使用者就需要大规模的修改自己的代码, 维护成本较高。
使用 private 封装属性, 并提供 public 方法供类的调用者使用:
具体代码示例如下:

class Person{
    private String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;
    public void eat(){
        System.out.println(name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println(count);//编译通过,可以运行
        //System.out.println(age);编译报错,不可以运行
        System.out.println("睡觉");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }

    public void show(){
        System.out.println("姓名:"+name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "bit";//出现编译报错
        person1.age = 10;
        System.out.println(person1);
    }
    }

编译报错原因:此时name字段已经使用 private 来修饰,类的调用者(main方法中)不能直接使用,而需要借助getter( )和 setter( )方法。此时类的使用者就不必了解 Person 类的实现细节,private 不光能修饰字段, 也能修饰方法。通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public, 就需要视具体情形而定。一般我们希望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public。

4.2 Getter和Setter方法

当上面代码中我们使用 private 来修饰字段的时候, 就无法直接使用这个字段了,而需要借助getter( )和 setter( )方法,具体代码示例如下:

class Person{
    private String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;

    //快捷键alt+insert 生成Getter、Setter方法
    public String getName(){
        return name;
    }
  /*  public void setName(String myName){
        name = myName;
        //this.name = myName;
    }*/
    public void setName(String name) {
        System.out.println("name:"+name);
        //name = name;局部变量,优先使用,不能这样写
        this.name = name;
    }
    public void eat(){
        System.out.println(this.name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println(count);//编译通过,可以运行
        //System.out.println(age);编译报错,不可以运行
        System.out.println("睡觉");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + this.name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person1 = new Person();
        //person1.name = "bit";
        person1.setName("bit");
        person1.age = 10;
        //System.out.println(person1.getName());
        System.out.println(person1);
    }
    }
  1. getName 即为 getter 方法, 表示获取这个成员的值;
    setName 即为 setter 方法, 表示设置这个成员的值
  2. 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例的引用。
  3. 不是所有的字段都一定要提供 setter / getter 方法, 而是要根据实际情况决定提供哪种方法。
  4. 在 IDEA 中可以使用 alt + insert (或者 alt + F12) 快速生成 setter / getter 方法;在 VSCode 中可以使用鼠标右键菜单 -> 源代码操作中自动生成 setter / getter 方法。

5 构造方法

5.1 了解构造方法

什么是构造方法?
答:写法:没有返回值,方法名称和类名是一样的。
实例化一个对象分为几步?
答:1.为对象分配内存。 2.调用合适的构造方法,合适意味着不只一个构造方法。
当第2步完成之后就会产生一个对象。
具体代码示例如下:

class Person{
    private String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;

    public Person(){
        System.out.println("不带有参数的构造方法");
    }
    public Person(String name){
        System.out.println("带有1个String类型的参数的构造方法");
    }
    public Person(String name,int age){
        System.out.println("带有2个参数,String类型、int类型的构造方法");
        this.name = name;
        this.age = age;
    }
    
    public String getName(){
        return name;
    }
    public void setName(String name) {
        System.out.println("name:"+name);
        //name = name;局部变量,优先使用
        this.name = name;
    }
    
    public void eat(){
        System.out.println(this.name + "吃饭");
    }
    //静态方法
    public static void sleep(){
        System.out.println(count);//编译通过,可以运行
        //System.out.println(age);编译报错,不可以运行
        System.out.println("睡觉");
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + this.name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }
    public static void func(){
        System.out.println(count);
        //System.out.println(this.count);
        System.out.println("static func()");
    }
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
     Person person1 = new Person()//调用不带参数的构造函数 
     Person person2 = new Person("feihan");//调用带有1个参数的构造函数
     Person person3 = new Person("fenhan",10);//调用带有2个参数的构造函数
     System.out.println(person3);
    }
    }

根据上述代码回答以下问题:
1. 这3个构造方法之间是什么关系?
答:重载关系。重载所需满足的三点要求:a.方法名称相同; b.参数列表不同(类型&个数); c.返回值不做要求。
2. 构造函数是否可以发生重载?
答:当然可以。
3. 如何调用这个合适的构造方法?
答:构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作。
4. 构造函数用来干嘛?
答:主要是用来构造对象,同时在构造对象的时候,我们还可以为对象进行成员的初始化!!!
注意: 当我们在写类的时候,如果一个构造函数都没有写的时候,那么编译器会默认生成一个不带有参数的构造方法。相反,如果你写了构造方法,那么编译器就不会为你默认生成不带有参数的构造方法了。
同时,我们要知道,Person person3 = new Person(“feihan”,10);这一句代码干了三件事情:1.分配内存; 2.调用构造方法; 3.赋值。

5.2 this关键字

this到底代表啥?
答:this代表当前对象的引用,但是有些书或者资料经常说this代表当前的对象,这句话是错误的。要习惯使用this关键字。
this:

1. this.访问成员变量。
例:this.name、this.age
2. this.调用成员方法。
例:this.show();
3. this( )调用构造方法。
!在一个方法的内部,调用另一个构造方法。
!!构造方法是不可以自己调用自己的。
!!!this( )只能放在第一行,且只能调一个,否则就会出现编译错误。
例:public Person( ) {
this (“bit”) ; //调用Person(String name)这个构造方法
System.out.println (“不带有参数的构造方法”) ;
}
public Person ( String name ) {
System.out.println ( “带有1个String类型的参数的构造方法” ) ;
}

具体代码示例如下:

class Person{
    private String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;

    public Person(){
        this("bit");//调用Person(String name)这个构造方法
        System.out.println("不带有参数的构造方法");
    }
    public Person(String name){
        System.out.println("带有1个String类型的参数的构造方法");
    }
    public Person(String name,int age){
        System.out.println("带有2个参数,String类型、int类型的构造方法");
        this.name = name;
        this.age = age;
    }

    //快捷键alt+insert 生成Getter、Setter方法
    public String getName(){
        return name;
    }
    public void setName(String name) {
        System.out.println("name:"+name);
        //name = name;局部变量,优先使用
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + this.name + ''' +
                ", age=" + age +
                ", flg=" + flg +
                ", ch=" + ch +
                ", sex='" + sex + ''' +
                '}';
    }

    public static void func(){
        System.out.println(count);
        System.out.println(this.count);//这里会编译报错
        System.out.println("static func()");
    }
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        Person person3 = new Person("feihan",10);
        System.out.println(person3);
    }
    }

注意: 静态方法内部,不能用this,原因是静态的不依赖对象,这也就是上面代码编译报错处的原因。
总结: 对于this和static来说:

  1. 静态方法内部,不能用this;且不能访问非静态的数据。
  2. 普通的方法内部是可以访问静态的数据的。
  3. 不管当前方式是静态的方法,还是非静态的方法,内部都不可以定义静态的变量。原因:因为静态的变量属于类,不属于方法。

6 代码块

代码块分为以下4种:

  1. 本地代码块(了解即可,不会用)。
  2. 实例代码块(构造代码块)。
  3. 静态代码块。
  4. 同步代码块(后面多线程会讲述)。

6.1 本地代码块

本地代码块的具体代码示例如下:

public class TestDemo2 {
    public static void main(String[] args) {
    int a = 10;
      { //本地代码块
        int a = 199;//这里重定义了,会报错
      }
    }
    }

6.2 实例代码块

它不在方法里面,它在类里面,具体代码示例如下:

class Person{
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
    
    {
        System.out.println("实例代码块");
    }
}

6.3 静态代码块

  1. 静态代码块先执行,接下来是实例代码块,最后是构造方法。
  2. 静态代码块只执行1次。

具体代码示例如下:

class Person{
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
    
    {
        size = 1000;
        System.out.println("实例代码块");
    }

    static {
        count = 999;
        //size = 1000;error
        System.out.println("静态代码块");
    }
}
public class TestDemo2 {
    public static void main(String[] args) {
        System.out.println(Person.count);
        Person person1 = new Person();
    }
    }

静态代码块和实例代码块的作用是干嘛的?
答:一般就是提前初始化一些数据。
如果都是静态的或者都是实例的先初始化谁?
答:和你代码的书写顺序是有关系的。
注意: 静态的不依赖对象,没对象之前,静态的都会执行,只要你开始运行代码;但是实例的成员,肯定都是需要对象的。

7 toString方法

详见本篇博客2.1 类和类的实例化部分对于toString方法的介绍。
我们刚刚注意到,我们在把对象的属性进行打印的时候,都自己实现了show函数,其实,我们大可不必。可以使用 toString 这样的方法来将对象自动转成字符串。

  1. toString 方法会在 println 的时候被自动调用。
  2. 将对象转成字符串这样的操作我们称为序列化。
  3. toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法实现我们自己版本的转换字符串方法。
  4. @Override 在 Java 中称为 “注解”, 此处的 @Override 表示下面实现的 toString 方法是重写了父类的方法。
  5. IDEA快速生成Object的toString方法快捷键:alt+f12(insert)。

8 匿名对象

匿名对象就是没有名字的对象,没有引用的对象称为匿名对象,匿名对象只能在创建对象时使用,适用于只用一次。如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象。
具体代码示例如下:

class Person{
    private String name;
    public int age;//int默认的0值就是0
    public static int count = 10;//静态成员变量 只有一份 在方法区
    public boolean flg;
    public char ch;
    public String sex;
    public int size;
    public void show(){
        System.out.println("姓名:"+this.name+"年龄:"+age);
    }
}
public class TestDemo2 {
    public static void function2(Person person){
    
    }
    public static void main(String[] args) {
        function2(new Person());
        System.out.println("==============");
        Person person2 = new Person();
        function2(person2);

        new Person().show();//这就是一个匿名对象
        new Person().show();//当又调用show()方法,你继续new Person().show();就可以了
        System.out.println("==============");
        Person person1 = new Person();
        person1.show();
        person1.show();
    }
    }

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>