java 类和对象的学习【详解篇8】

一、类和对象的初步认识

简单理解类和对象

类和对象,它是比较抽象的概念

什么是类?

类在Java当中也叫自定义类型,类相当于一个模板,对象是由模板产生的样本。比如把类想象成一个做果冻的模子,通过这个模子可以做出一个具有形状的果冻,通过不同的模子,也可以做出形状各异的果冻。因此,我们可以知道,通过一个类可以产生多个对象。

image-20210821170918879

什么是类的实例化?

用类类型创建对象的过程,称为类的实例化

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

如下图:把类想象成一张图纸,根据这张图纸,可以建造出一栋或多栋跟图纸上看着一样的可以住的房子,也就是把抽象的东西变成了具体存在的东西。以上通过一个模板可以产生多个实体,也就是说,一个类可以实例化出多个对象

image-20210821165929748

什么是对象?

可以把对象想象成实体

什么是面向对象?

1.面向对象是思考问题的一种思考方式,是一种思想。比如:概念与实例。理论与实践。名和实等等。

2.类就是一类对象的统称。对象就是这一类具体化的一个实例。

3.面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。

面向对象和面向过程的区别是什么?

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

面向过程注重的是过程,它指的是在整个过程中所涉及的行为,也就是功能。

面向对象注重的是对象,也就是参与过程所涉及到的主体,通过逻辑将一个个功能实现连接起来。

面向过程的例子1: 1.把冰箱打开 2. 把大象放进去 3. 冰箱关起来
面向对象的例子1: 打开冰箱,储存,关闭这都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中。

面向过程的例子2: 面向过程就是什么都得自己动手来做,注重过程,如:手洗衣服的过程,你需要自己拿盆、打水、放洗衣粉、搓洗、换水、拧干,晾晒等做的这些就是面向过程。
面向对象的例子2: 找到一个对象,让这个对象去做这些事情,你不需要自己动手去做,它做好之后你只需要拿过来用就好了。如:洗衣服不用手洗用全自动洗衣机洗,你只需放洗衣粉,之后它可以帮你去实现洗衣服的过程,洗好之后你只需要晾晒即可,这里全自动洗衣机和人就是对象。
因此面向对象的重点就是:找对象,创建对象,使用对象,并维护对象之间的关系。

简而言之

面向对象就是用代码(类)来描述客观世界的事物的一种方式,一个类主要包含是一个事物的属性和行为。

二、类和类的实例化

java当中如何定义一个类呢?

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

看以下简单的声明一个类。

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

class是定义类的关键字;
ClassName是类的名字;
{}大括号中的是类的主体;
类中的元素称为属性;
类中的函数称为成员方法

如:定义一个Person1类(人这种类型)

  1. 从代码层面来说对象通过类产生的,如人、洗衣机都是对象,而实实在在的人是由类产生的,写成代码就是class Person1{}表示当前我的类叫做Person1,即有一个类,类名为Person1,对于一个人来说,人有姓名、年龄、身高、体重、联系方式、住址等,这些被称为属性,也叫作成员变量。这些属性可以定义在类中。
  2. 自定义类使用关键字class,class后跟的是类型的名字Person1,类名要使用大驼峰的形式写。
  3. 一个类是由字段和方法共同组成的。
  4. 字段也叫成员属性/成员变量,如:age,name,sex。
  5. 方法就是成员方法,也叫行为,如:eat(),sleep()。
  6. public(共有的)叫做访问修饰限定符,java中的访问修饰限定符不仅仅有public,还有private(私有的),还有protected(受保护的)。
  7. 成员变量中的public也可以不写,不写表示默认权限,也就是包访问权限,这里先不细说,写的时候先加上。

代码示例:这,就是定义了一个类,类名叫Person1,它有三个字段age,sex,name和两个方法eat()和sleep()

class Person1{
    public int age;//成员属性,也叫字段/成员变量
    public  String sex;
    public  String name;
    public void eat(){//成员方法,也叫行为
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"不爱吃饭!");
    }
    public void sleep(){
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"爱睡觉!");
    }
    /*
    注意事项:这里成员方法的写法和之前写的方法不同, 此处写的方法不带 static 关键字*/
}

类定义完成之后,如何去用呢?

定义出Person1这种类型之后,就可以通过这种Person1类型来定义变量person1,此时就说person1的这个变量的类型就是Person.

public static void main1(String[] args) {
            Person1 person1;
  • 注意:变量的命名是自定义的,不固定的,想写成什么都可以,但尽量有意义。

变量定义完成之后,需要通过赋值,使用new来产生对象,写法为:

//产生对象          实例化对象
Person1 person1 = new Person1();
  • 这个过程也叫实例化一个对象Person1,此时人这个对象就产生了。

上面说过一个类可以产生多个对象,为什么说可以产生多个对象呢?那它如何产生对象的呢?如何用代码表示呢?

  • 一个类产生多个对象,就是说可以通过Person1这一个类,来定义多个变量,再通过new关键字实例化对象之后,这些对象就产生了。

代码表示如下:

Person1 person1 = new Person1();//通过关键字new,实例化一个对象
Person1 person2 = new Person1();
Person1 person3 = new Person1();
Person1 person4 = new Person1();

结合以上,写成完整的代码如下:

class Person1{
    public int age;//成员属性,也叫字段/成员变量
    public  String sex;
    public  String name;
    public void eat(){//成员方法,也叫行为
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"不爱吃饭!");
    }
    public void sleep(){
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"爱睡觉!");
    }
    /*注意事项:这里成员方法的写法和之前写的方法不同, 此处写的方法不带 static 关键字*/
}
public static void main(String[] args) {
              Person1 person1 = new Person1();//通过关键字new,实例化一个对象
              Person1 person2 = new Person1();
              Person1 person3 = new Person1();
              Person1 person4 = new Person1();
}

注意:

1.new 关键字用于创建一个对象的实例.

2.使用 . 来访问对象中的属性和方法.

3.同一个类可以创建对个实例

三.类的成员

成员变量学习内容

如何使用字段呢?

定义完 Person1 person1 = new Person1();之后,person1是在main函数里面的,person1是个变量,因为局部变量都在栈上放着,所以它的内存布局是这样的。

image-20210825224514058

字段是在类的里面,方法的外面定义的,因此它是成员变量,如果是成员变量,它是在对象里面的,但并不是所有的成员变量都在对象里面,只有实例成员变量才在对象里面。

那么什么不是成员变量呢?是怎么定义的呢?

如:在类中这样定义的变量size就不在对象里面,这个size叫静态成员变量。

class Person1{
    public int age;//实例成员变量
    public  String name;
    public static int size=10;//静态成员变量
}

加了static就是静态成员变量,不加的就叫实例成员变量,name和age、sex在对象里面,对象在堆上,因此堆上的对象里面就有一个name、age、sex,假设对象的地址是0x666,那么变量person1这个变量里面存的也是0x666,此时person1就指向了这个对象,这个对象里面有name、age、sex。

image-20210825224602929

如何访问对象当中的实例成员变量呢?

通过点操作符,对象的引用.成员变量

如:person1.age

System.out.println(person1.age);表示打印person1所指的new Person1这个对象里面的age。

局部变量一般情况下要赋初值,因此如果不打印的话会报错,但在这里如果实例成员变量没有初始化就打印的话,就不会报错,因为当实例成员变量没有初始化的时候,默认为对应的初值。

默认值规则

引用类型默认为null
基本类型默认为0
boolean默认为false
char类型默认为’\u0000’

验证默认值规则代码示例:

class Person1{
    public int age;//成员变量,未初始化
    public  String sex;
    public  String name;
    public char ch;
    public boolean flg;
}
public static void main(String[] args) {
              Person1 person1 = new Person1();//通过关键字new,实例化一个对象
              System.out.println(person1.age);//实例成员变量没有初始化就打印
              System.out.println(person1.name);
              System.out.println(person1.ch);
              System.out.println(person1.flg);
    
}

打印结果:image-20210824072146696

实例成员变量可以直接初始化,但一般情况下,实例成员变量不会直接给它初始化,看一下直接初始化的方式。

直接初始化代码示例:

class Person1{
    public int age=10;//成员变量,已初始化
    public  String sex="女";
    public  String name="小小";
}
public static void main(String[] args) {
              Person1 person1 = new Person1();
              System.out.println(person1.name);//实例成员变量初始化打印
              System.out.println(person1.sex);
              System.out.println(person1.age);
}

打印结果:小小
        女
        10

为什么一般情况下,实例成员变量不会直接给它初始化呢?

因为,成员变量在main函数里面也可以初始化,如果在类中直接初始化了,那在main函数里面再次初始化为不同的值的话,值就会被改变,其结果会按在main函数里面初始化的值打印。

所以,一般情况下,实例成员变量不会在类中直接给它初始化的

代码示例:

class Person1{
    public int age=10;//成员变量,已初始化
    public  String sex="女";
    public  String name="小小";
}
public static void main(String[] args) {
              Person1 person1 = new Person1();
              System.out.println(person1.name);//实例成员变量在类中初始化打印
              System.out.println(person1.sex);
              System.out.println(person1.age);
              System.out.println("================");
              person1.name="大大";实例成员变量在main函数里的初始化方式
              person1.age=11;
              person1.sex="男";
              System.out.println(person1.name);//实例成员变量在main函数里初始化打印
              System.out.println(person1.sex);
              System.out.println(person1.age);
       
}

打印结果:image-20210824074305518

以上就是成员变量的访问形式。

注意:

1、使用 . 访问对象的字段.

2、“访问” 既包含读, 也包含写.如:可以修改name,也可以打印name”

3、对于一个对象的字段如果没有显式设置初始值, 那么会被设置一个默认的初值.

默认值规则

1、对于各种数字类型, 默认值为 0.

2、对于 boolean 类型, 默认值为 false.

3、对于引用类型(String, Array, 以及自定制类), 默认值为null
4、char类型默认为’\u0000’

如何访问静态成员变量呢?

当静态成员变量没有初始化的时候,默认为对应的0值(根据默认值规则)。

当静态成员变量初始化的时候,对应的值为初始化的值。

静态成员变量不在对象里面,因此就不在堆上的对象里面,那么它在哪里呢?它存在方法区(JVM里面的方法区)里面。后面会说。

静态成员变量不属于对象,它属于类Person1,要想访问它,不需要再new实例化对象,直接通过类名.静态成员变量就可以访问。

class Person1{
    public static int size;//未初始化的静态成员变量
}
public class TestClass {
    public static void main1(String[] args) {
        System.out.println(Person.size);//类名.静态成员变量
    }
}
打印结果:0

成员方法的学习内容

如何调用实例成员方法?

没有加static的成员方法就叫实例成员方法。

可以通过对象的引用来访问方法,即对象的引用.实例成员方法.

方法不属于对象,方法是不能放到对象里面去的。

如果在成员方法里面定义一个局部变量a,那这个a是在栈里面存放的

class Person1{
    public void eat(){//成员方法,也叫行为
        int a=10;//局部变量
        System.out.println("eat()");
    }
    public void sleep(){
        System.out.println("sleep()");
    }
    /*
    注意事项:这里成员方法的写法和之前写的方法不同, 此处写的方法不带 static 关键字*/
}
public static void main(String[] args) {
              Person1 person1 = new Person1();//通过关键字new,实例化一个对象
              person1.eat();//对象的引用.实例成员方法
}
打印结果:eat()
        sleep()
如何调用静态成员方法?

加static的成员方法就叫静态成员方法。

和静态成员变量一样,静态成员方法不属于对象,它属于类Person1,要想访问它,不需要再new实例化对象,直接通过类名.静态成员方法就可以访问。

class Person1{
    public static void func1(){//静态成员方法
        System.out.println("static:func1");
    }
}
public static void main(String[] args) {
              Person1.func1();//类名.静态成员方法
}

打印结果:static:func1    

一个类可以实例化多个对象,每实例化一个对象,它就会在堆中新生成一个对象,也会在栈中增加一个变量,这个变量指向这个对象,每个对象里面都有name、age、sex,但静态成员变量size还是只有一份,它存在方法区(JVM里面的方法区)里面。内存布局如图。

image-20210825233036263

代码示例:

class Person1{
    public int age;//成员属性,也叫字段/成员变量
    public  String sex;
    public  String name;
    public static int size;//静态成员变量
    public void eat(){//成员方法,也叫行为
         int a=10;//局部变量
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"不爱吃饭!");
    }
    public void sleep(){
        System.out.println("姓名:"+name+" "+"年龄"+age+" "+"爱睡觉!");
    }
}
public static void main(String[] args) {
              Person1 person1 = new Person1();//通过关键字new,实例化一个对象
              Person1 person2 = new Person1();
              Person1 person3 = new Person1();
             
}

认识null

null 在 Java 中为 “空引用”, 表示不引用任何对象. 类似于 C 语言中的空指针. 如果对 null 进行 . 操作就会引发空指针异常.

class Person3{
    public String name;//字段/属性/成员变量
    public int age;
    public boolean flg;
}
 public static void main(String[] args) {
            Person3 person = new Person3();
            System.out.println(person.name.length());//没有给name赋初值,name就是null,person.name为空,空再去访问字符串长度肯定拿不到,就会出现空指针异常。
        }
点号之前不是null就OK,点号之前是null必然就会报错

打印结果:image-20210824092444634

字段就地初始化

很多时候我们不希望字段使用默认值, 而是需要我们显式设定初值. 可以这样写:

class Person4{
    public String name="李明";//显式设定初值
    public int age=18;
}
public static void main(String[] args) {
            Person4 person = new Person4();
            System.out.println(person.name);
            System.out.println(person.age);
        }
//打印结果:李明
           18
  • 但其实这个上面我们也说了,实例成员变量在类中直接给它初始化的方式,不推荐。

方法 (method)

方法就是用于描述一个对象的行为.

class Person5{
    public String name="王二";
    public int age=22;
    public String sex="男";
    public void  show(){//成员方法: show 方法, 表示 Person 这个对象具有一个 "展示自我" 的行为.
        System.out.println("我叫"+name+" "+"今年"+age+"岁"+" "+"性别"+sex+" "+"爱好女");
    }
}
 public static void main(String[] args) {
            Person5 person1 = new Person5();
            person1.show();// 调用show方法, show 方法是和 person1 实例相关联的. 如果创建了其他实例,也就是重新赋值, 那么 show 的行为就会发生变化
            Person5 person2 = new Person5();
            person2.name = "李四";
            person2.age = 20;
            person2.show();
        }

打印结果:image-20210824093703546

方法中还有一种特殊的方法称为 构造方法 (construction method)
在实例化对象的时候会被自动调用到的方法, 方法名字和类名相同, 用于对象的初始化.
虽然我们前面已经能将属性就地初始化, 但是有些时候可能需要进行一些更复杂的初始化逻辑, 那么就可以使用构造方
法.后面会详细介绍构造方法的语法.

static 关键字

1、修饰属性
2、修饰方法
3、代码块
4、修饰类

修饰属性:Java静态属性和类相关, 和具体的实例无关. 换句话说, 同一个类的不同实例共用同一个静态属性(即:解释上面画的内存布局中为什么static只有一份)

代码示例:

class TestDemo1{
    public int a;
    public static int count;//静态属性

}
public static void main(String[] args) {
            TestDemo1 t1 = new TestDemo1();
            t1.a++;
            TestDemo1.count++;//count被static所修饰,所有类共享。且不属于对象,访问方式为 类名.属性
            System.out.println(t1.a);
            System.out.println(TestDemo1.count);
            System.out.println("============");
            TestDemo1 t2 = new TestDemo1();
            t2.a++;//每new一个对象,那这个对象的成员变量都有一份新的在对象当中,再++的时候,加的是新的变量a
            TestDemo1.count++;//count是一个静态的,它只有一份在方法区当中,因此再++的时候,加的还是上一份
            System.out.println(t2.a);
            System.out.println(TestDemo1.count);
        }
打印结果:
1
1
============
1
2

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

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

class TestDemo2{
    public int a;//非静态数据成员
    public static int count;//静态数据成员
    
    public static void change() {//静态方法
        count = 100;
        //a = 10; error 静态方法内部不可以访问非静态数据成员
    }
}
public static void main02(String[] args) {
            TestDemo2.change();//无需创建实例对象 就可以调用静态方法
            System.out.println(TestDemo2.count);
}
//打印结果:
100
    
/*
*/

注意事项1:

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

注意事项2

(1)我们曾经写的方法为了简单, 都统一加上了
static,因为静态的只能调用静态的,如果想要调用非静态的就需要实例化对象,通过引用来调用. 但实际上一个方法具体要不要带 static,都需要是情形而定。

如:

public class TeatDemo2{
      public static void func1(){
      
      }
      public  void func2(){
      
      }
}
public static void main02(String[] args) {
           TestDemo2.func1();//静态的只能调用静态的
           TestDemo testDemo2=new TestDemo2();//非静态的就需要实例化对象
           testDemo2.func2();//通过引用来调用
}

(2)main 方法为 static 方法。

观察以下代码, 分析内存布局

class Person6 {
    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 void eat() {  //实例成员函数(方法)
    int a = 10;//局部变量
    System.out.println("eat()!");
    }
    public void sleep() {  //实例成员函数(方法)
    System.out.println("sleep()!");
    }
    
    public static void staticTest(){  //静态成员函数(方法)
    //sex = "man"; error: //不能访问非静态成员
    System.out.println("StaticTest()");
    }
}
 public class TeatClassAndObject {
 public static void main(String[] args) {
            //产生对象 实例化对象
            Person6 person = new Person6();//person为对象的引用
            System.out.println(person.age);//默认值为0
            System.out.println(person.name);//默认值为null
            //System.out.println(person.count);//按说会有警告,但没有,为什么?
            //正确访问方式:
            System.out.println(Person6.count);//类名.属性
            System.out.println(Person6.COUNT);
            Person6.staticTest();//类名.静态成员函数(方法)
            //总结:所有被static所修饰的方法或者属性,全部不依赖于对象。
            person.eat();//实例成员函数(方法)
            person.sleep();
        }
 }

打印结果:image-20210824114022770

画图观察:

image-20210825235326106

四、封装

什么叫封装?

<<代码大全>> 开篇就在讨论一个问题: 软件开发的本质就是对程序复杂程度的管理. 如果一个软件代码复杂程

度太高, 那么就无法继续维护. 如何管理复杂程度? 封装就是最基本的方法.

封装就是用private(访问修饰限定)来修饰属性或者方法。

为什么要封装?

在我们写代码的时候经常会涉及两种角色: 类的实现者类的调用者.

封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.这样就降低了类使用者的学习和使用成本,
从而降低了复杂程度。

说人话就是,因为一般写项目的时候类的实现者和类的调用者是两个不同的人完成的,如果是public修饰的话,如果有一天类的实现者将属性改了,可能类的调用者都不知道,这会导致代码发生错误,修改起来也比较复杂。

private/ public的区别?

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

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

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

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

说人话就是,如果一个属性或者方法被private修饰之后,他只能在类当中使用所修饰的这个属性,在类外是不能够被访问到的,即private(访问修饰限定)限定你只能在类当中访问。

public修饰属性代码示例:

class Person7{
    public String name = "张三";//public修饰字段
    public int age = 18;
} 
public static void main(String[] args) {
            Person7 person = new Person7();
            System.out.println("我叫" + person.name + ", 今年" + person.age + "岁");
//打印结果:我叫张三, 今年18岁
    
/*这样的代码导致类的使用者(main方法的代码)必须要了解 Person 类内部的实现, 才能够使用这个类. 学习成本较高
一旦类的实现者修改了代码(例如把 name 改成 myName), 那么类的使用者就需要大规模的修改自己的代码, 维
护成本较高*/
  }

private修饰属性代码示例:使用 private 封装属性, 并提供 public 方法供类的调用者使用.

class Person8{
    private String name = "小张三";//private修饰字段
    private int age = 16;
    
    public void func1(){
         System.out.println("func1()");
    }
    public void show() {
        System.out.println("我叫" + name + ", 今年" + age + "岁");
    }
}
//以上是类的实现者写的代码

//以下是类的调用者写的代码
 public static void main(String[] args) {
            Person8 person = new Person8();
            person.show();
 }
//打印结果:
我叫小张三, 今年16/*
此时字段已经使用 private 来修饰,类的调用者(main方法中)不能直接使用, 而需要借助 show 方法, 此时类的使用者就不必了解 Person 类的实现细节;
同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改(类的调用者根本访问不到 name, age这样的字段).
那么问题来了~~ 类的实现者万一修改了 public 方法 show 的名字, 岂不是类的调用者仍然需要大量修改代码吗?
这件事情确实如此, 但是一般很少会发生. 一般类的设计都要求类提供的 public 方法能比较稳定, 不应该频繁发生大的改变.
尤其是对于一些基础库中的类, 更是如此. 每次接口的变动都要仔细考虑兼容性问题.
*/

注意事项:

1.private 不光能修饰字段, 也能修饰方法
2.通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public, 就需要视具体情形而定. 一般我们希望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public.getter和setter方法
3.当我们使用 private 来修饰字段的时候, 类的调用者(main方法中)就无法直接使用这个字段了,也就是说在类外就不能访问私有的数据成员了.如果需要获取或者修改这个 private 属性, 就需要使用 getter / setter 方法来访问这些属性.
4.使用 private 来修饰字段有利于程序更好的维护

getter和setter方法和关键字this的使用

代码示例:

class Person9{
    private String name;//实例成员变量
    private int age;
    private String sex;
    
//提供一个公开的接口
    public void setName(String name) {//设置这个成员的值,String name是参数,它的作用域是这个大括号
        this.name = name; //this代表当前对象的引用(当前对象是Person9,引用是Name ),表示调用该方法的对象
        //name = name;//不能这样写,这样写是自己给自己赋值,并没有赋值属性,因为局部变量优先
    }
    public String getName() {//获取这个成员的值
        return name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public void show(){
        System.out.println("name: "+this.name+" age: "+this.age+" "+"sex:");
    }
    //如果不想写show方法的话,可以使用Object重新实现一下Object类的toString()方法
    //快捷键:alt+insert  -->选择toString()
    //Object 是所有类的父类
    @Override//@Override叫注解:这个注解指的是这个方法是重新写的
    public String toString() {
        return "Person9{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//以上是类的实现者写的代码

//以下是类的调用者写的代码
public static void main(String[] args) {
            Person9 person = new Person9();
            person.setName("小张");//设置这个成员的值
            String name = person.getName();//获取这个成员的值
            System.out.println(name);
            person.setAge(18);
            int age = person.getAge();
            System.out.println(age);
            person.show();//同时打印name和age需要调用show方法
            System.out.println(person);//打印toString方法

        }

打印结果:image-20210824134005157

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

五、构造方法

疑问1:一个对象的产生分为几步,它是如何产生的?(new 执行过程)

第一步:为对象分配内存空间

第二步:调用合适的构造方法

疑问2:什么是构造方法?

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

语法规则

1.方法名称必须与类名称相同

2.构造方法没有返回值类型声明

3.每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)

代码示例:

class Person10{
    private String name;//实例成员变量
    private int age;
    public Person10() { //它就是构造方法,它的类名是和它的方法名相同,且没有返回值。
        System.out.println("呵呵");
    }
     public static void main10(String[] args) {
            Person10 person1=new Person10();//new Person10()就调用了构造方法
     }

注意:

1.当没有提供构造方法的时候,实例化对象之后,编译器会默认提供一个不带有参数的构造方法,因此也是能够打印的,只不过没有打印结果。

2.但是一旦你提供了构造方法,编译器就不会再自动生成一个构造方法了。

3.要实例化出一个对象的话,必须调用它的构造方法。

4.构造方法支持重载. 规则和普通方法的重载一致。

疑问3:为什么要提供构造方法呢?

因为对象的产生是需要调用构造方法的

疑问4:构造方法的作用是什么?

从本质上来说,它是用来构造对象的或者说是实例化一个对象的。

疑问5:什么是合适的构造方法?这样说意味着构造方法不止一个?

什么时候,调用哪个构造方法,取决于你main方法中的实例化对象有没有给参数。

代码示例:

class Person10{
    private String name;//实例成员变量
    private int age;
    private String sex;
    public Person10() { //默认构造函数,不带有参数的构造函数 构造对象
        this.name = "小夏";
        this.age = 25;
        this.sex = "女";
        System.out.println("呵呵");
    }
    public Person10(String name, int age, String sex) {//带有3个参数的构造函数
        //构造函数不能重复,但是可以写成带参数的构造函数,构造对象的同时,就可以把姓名、年龄、性别传过来,这样就可以不用setter和getter方法了,其实他们本质上没有太大的不同,都是要给属性赋值的, 但是setter和getter方法更灵活。
        //赋值方式如下:
        this.name = name;
        this.age = age;
        this.sex = sex;
        System.out.println("哈哈");
    }
    public void show() {
        System.out.println("name: " + name + " age: " + age + " sex: " + sex);
    }
}
  public static void main10(String[] args) {
            Person10 person1=new Person10();//调用不带有参数的构造函数
            person1.show();
            Person10 person2=new Person10("小杨",27,"男");//调用带有参数的构造函数,且第一个参数是字符串,第二个是整型,第三个是字符串
            person2.show();        
        }
//打印结果:
呵呵
name: 小夏 age: 25 sex: 女
哈哈
name: 小杨 age: 27 sex:

疑问6:构造方法可以自动生成吗 ?

可以,快捷键是:alt+insert–>Constructor–>回车,选中一个就会生成带有一个参数的构造函数,选中两个就会生成带有两个参数的构造函数。

面试问题:this关键字代表对象,这句话是否正确 ?

不正确,它代表当前对象的引用。那为什么不能代表对象呢 ?

因为一个对象的产生分为2步,第一是为对象分配内存,第二是调用合适的构造方法。

只有构造方法走完之后才有对象,而this在产生对象的过程当中就已经使用了,所以this不能代表对象。而为对象分配内存就产生了地址,因此this代表的是当前对象引用。

this关键字

this表示当前对象引用(注意不是当前对象,而是当前对象引用). 可以借助 this 来访问对象的字段和方法。

this的作用:

this():表示调用自己的构造方法

注意:它只能在构造方法里面写,因为它只能写在第一行,所以它只能调用一次。

this.data:调用当前对象的属性

this.func():调用当前对象的方法

重载满足的方法:

1.方法名称相同

2.参数列表不同

3.返回值不做要求

重载发生的前提:在同一个类当中

面试问题:构造方法支不支持重载?

支持,它的规则和普通方法的重载一致。

this关键字的使用

代码示例:

class Person11{
    private String name;//实例成员变量
    private int age;
    private String sex;
    //默认构造函数 构造对象
    public Person11() {
        //this调用构造函数
        this("小巴",18,"女");//此时this调用的是下面带有参数的构造方法,写它的时候必须放在第一行进行显示
    }
    //这两个构造函数之间的关系为重载。
    public Person11(String name,int age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
         System.out.println("name: "+name+" age: "+age+" sex: "+sex);
    }
}
public static void main11(String[] args) {
            Person11 person = new Person11();//它调用不带参数的构造函数
                      
// 我们会发现在构造函数的内部,我们可以使用this关键字,构造函数是用来构造对象的,我们就使用了this,那this还代表当前对象吗?
// 当然不是,this代表的是当前对象的引用。函数是用来构造对象的,对象还没有构造好,代表的是当前对象的引用。
        }
 //打印结果:
name: 小巴 age: 18 sex:

六、认识代码块

字段的初始化方式有:

  1. 就地初始化
  2. 使用构造方法初始化
  3. 使用代码块初始化
    前两种方式前面已经学过,接下来介绍第三种方式, 使用代码块初始化。

什么是代码块?

代码块就是使用大括号 { } 定义的一段代码。

根据代码块定义的位置以及关键字,又可分为以下四种:

(1)普通代码块
(2)构造块也叫实例代码块
(3)静态代码块
(4)同步代码块(后续讲解多线程部分再谈)

普通代码块:定义在方法中的代码块.

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); 
 } 
} 
// 执行结果
x1 = 10 
x2 = 100

构造块(也叫实例代码块)

构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量

class Person12{
    private String name;//实例成员变量
    private int age;
    private String sex;
    public Person12(){//构造方法
        System.out.println("I am a student()!");
    }
    //实例代码块(构造代码块):一般用于初始化实例成员变量
    {
        this.name="小十二";
        this.age=12;
        this.sex="man";
        System.out.println("I am instance init()!");
    }
    public void show(){
        System.out.println("name:"+name+" "+"age:"+age+" "+"sex"+sex);
    }
}
public static void main(String[] args) {
        Person12 person=new Person12();
        person.show();
}
//打印结果:实例代码块优先于构造函数执行。
I am instance init()!
I am a student()!
name:小十二 age:12 sexman
   

静态代码块

使用static定义的代码块。一般用于初始化静态成员属性。

静态的方法和静态的成员是不依赖于对象的,可以通过类名来进行访问。
如果静态方法里面访问了实例成员变量,那么这个实例成员变量是依赖对象的。但静态方法不依赖。
静态的内容,只会被执行一次,而且是最早被执行的。

常考题:代码块执行的先后顺序。
/*使用static定义的代码块。一般用于初始化静态成员属性。*/
class Person13{
    private String name;//实例成员变量
    private int age;
    private String sex;
    private static int count = 0;//静态成员变量 由类共享数据 方法区

    public Person13(){
        System.out.println("I am Person init()!");
    }
    //实例代码块
    {
        this.name="小十三";
        this.age=13;
        this.sex="男";
        System.out.println("I am instance init()!");
    }
    //静态代码块:使用static定义的代码块。一般用于初始化静态成员属性。
    static {
        //this.name="张三";//error:它里面不能访问非静态的数据成员
        count=10;//只能访问静态数据成员
        System.out.println("I am static init()!");
        System.out.println("count="+count);
    }
    public void show(){
        System.out.println("name:"+name+" "+"age:"+age+" "+"sex:"+sex);
    }
}
 public static void main13(String[] args) {
            Person13 person1=new Person13();
            Person13 person2=new Person13();
            Person13 person3=new Person13();
            person1.show();
     
     
//打印结果:先打印静态代码块,再打印实例代码块,最后打印构造函数
I am static init()!
I am instance init()!
I am Person init()!
I am instance init()!
I am Person init()!
I am instance init()!
I am Person init()!

        }

注意事项(常考题:)

1、静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
2、静态代码块执行完毕后,实例代码块(构造块)执行,再然后是构造函数执行。

七、toString 方法和匿名对象

toString 方法

我们在把对象的属性进行打印的时候,都自己实现了show函数,其实,大可不必。接下来我们看一些示例代码:
代码示例:

class Person14{
    private String name;
    private int age;
    public Person14(String name,int age){
        this.age=age;
        this.name=name;
    }
    public void show(){
        System.out.println("name:"+name+" " + "age:"+age);
    }
}
 public static void main(String[] args) {
            Person14 person=new Person14("小十四",14);
            person.show();
            System.out.println(person);//我们发现这里打印的是一个地址的哈希值 原因:调用的是Object的toString方法
 }
//打印结果:
name:小十四 age:14 
Person@1c168e5
        

可以使用 toString 这样的方法来将对象自动转换成字符串
代码示例:

class Person15{
    private String name;
    private int age;
    public Person15(String name,int age){
        this.age=age;
        this.name=name;
    }
    public void show(){
        System.out.println("name:"+name+" " + "age:"+age);
    }
    //重写object的toString方法
    @Override
    public String toString() {
        return "Person15{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public static void main(String[] args) {
            Person15 person=new Person15("小十五",15);
            person.show();
            System.out.println(person);
}

//打印结果:
name:小十五 age:15
Person15{name='小十五', age=15}              

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

匿名对象

匿名只是表示没有名字的对象.

1.没有引用的对象称为匿名对象.
2.匿名对象只能在创建对象时使用
3.如果一个对象只使用一次,后面不需要用了,可以考虑使用匿名对象
4.匿名对象只能使用一次。

class Person16 {
    private String name;
    private int age;

    public Person16(String name, int age) {
        this.age = age;
        this.name = name;
    }
    public void show() {
        System.out.println("name:" + name + " " + "age:" + age);
    }
}
    public class TeatClassAndObject {
        public static void main16(String[] args) {
            new Person16("小十六",16).show();//通过匿名对象调用方法
        }
    }
 //打印结果:
name:小十六 age:16

内容重点总结

一个类可以产生无数的对象,类就是模板,对象就是具体的实例。

类中定义的属性,大概分为几类:类属性,对象属性。其中被static所修饰的数据属性称为类属性, static修饰的

方法称为类方法,特点是不依赖于对象,我们只需要通过类名就可以调用其属性或者方法

静态代码块优先实例代码块执行,实例代码块优先构造函数执行。

this关键字代表的是当前对象的引用。并不是当前对象。

拓展

面试问题:OOP语言的三大特征?

OOP指的是面向对象编程。
面向对象编程的语言有很多,如:JAVA,C++等
所以OOP语言的三大特征是:继承、封装、多态。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值