java基础-类和对象详解

Posted 爱敲代码的三毛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java基础-类和对象详解相关的知识,希望对你有一定的参考价值。



提示:以下是本篇文章正文内容,下面案例可供参考

一、类与对象的初步认知

1.面向过程和面向对象

在了解类和对象之前我们先了解一下什么是面向过程和面向对象。

面向过程编程:

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

面向对象编程:

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

来举个例子,就比如洗衣服:
在这里插入图片描述

面向过程:1.拿桶 2.把衣服放桶里 3.接水 4.放洗衣服 5.搓 6.再接水 7.把衣服拧干 8.晒衣服
面向对象:1.把衣服和洗衣粉放进洗衣机 2.打开洗衣机 3.把衣服拿出来晾干

在这里洗衣机就是一个对象,所以只要操作洗衣机所具备的功能,都要定义在对象中。

(1) 面向过程和面向对象的区别

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

2.类和对象

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

这样说可能太过于抽象
上面说了java是面向对像编程,如果我们先要找对象编程,首先就得找对象而对象是通过类产生的。
我们来举个通俗易懂的例子:
就比如建房子,类就相当于一个模板也就是图纸
在这里插入图片描述
而对象就是房子,也就是一个实体。只有通过图纸才能建房子。
在这里插入图片描述
所以只有通过类才能产生对象,我们以后开发其实就是:
找对象,建对象,用对象,并维护对象之间的关系。

二、类和类的实例化

1.类的定义

在java当中我们用 class 关键字来创建一个新的类型,我们把它叫做类。
一个类是由方法和字段组成
这里我来举一个例子,我用class定义了一个 People 类,来描述一个人。

class People{
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;

    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
}

class为定义类的关键字,People是类的名字,{}中为类的主体。
类中的元素称为:成员变量也就字段或者叫做成员属性。 这里面的name、age、sex 都是字段。
类中的方法称为:成员方法

字段(成员变量):定义在类的内部,方法的外部

2.实例化一个类

用类类型创建对象的过程,称为类的实例化
我们已经知道通过class关键字来定义一个类了,而我们知道类只是相当于一个模板,所以我们要通过类来实例化对象,由类产生对象的过程叫做 实例化一个对象。

代码如下(示例):

class People{//类名大驼峰
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;

    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
}
 
public class Test {
    public static void main(String[] args) {
        People p1 = new People();//示例化一个对象
    }
}

我们通过 new 关键字来实例化一个对象
在这里插入图片描述
一个类是可以实例化多个对象的,就比如我上面那个例子一个图纸是不是可以建很多房子。
在这里插入图片描述
在这里插入图片描述
通过 new 关键字我们是可以实例化多个对象的

public static void main(String[] args) {
        People p1 = new People();
        People p2 = new People();
        People p3 = new People();
}

3.类在内存中的存储

我们知道了如何定义类和通过类实例化对象,那么一个类在内存到底是如何存储的呢?

和数组一样类也属于于引用,而引用指向的是一个对象,p1和p2这些变量都是局部变量它们属于引用,我在前面数组的博客也讲到过局部变量是在栈上开辟内存的,引用里面存的是对象的地址,这些变量里存的都是引用每实例化一个对象就在堆区开辟一块内存。对象里面存的就是字段。

注意:类里面的方法并不是是存在堆区的 ,方法本身是不占内存的,方法是存在方法区里的方法表中,在每个对象 new 好之后前面有几个字节存的就是方法表的地址,只有在调用这个方法时,会通过方法表的地址找到这个这个方法,然后在栈上为这个方法开辟栈帧。当然这里只是简单介绍一下,到后面的博客中会详细讲解。
在这里插入图片描述

引用不一定是在栈上的!如果它是一个示例成员变量,那么它就是在堆上的,就比如这里的 name和 sex。

4.访问类的成员

我们知道了如何定义个和实例化一个对象,那么怎么访问这些成员变量呢?

成员变量的访问:对象的引用 . 属性名
成员方法的访问:对象的引用 . 方法名

class People{
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;
    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
}
public class Test {
    public static void main(String[] args) {
        People p1 = new People();
        System.out.println(p1.name);
        System.out.println(p1.sex);
        System.out.println(p1.age);
        p1.show();
    }
}

运行结果

在这里插入图片描述

注意:这里的成员变量并没有初始化,不同于局部变量不初始化会报错。成员变量不初始化是其类型对应的0值。

在这里插入图片描述

三、类的成员

1.成员变量的初始化

我们把定义在类的内部,方法的外部的变量叫“字段”或者叫它成员变量有时候也叫它“属性"。这三种叫法并没有严格区分。

public static void main(String[] args) {
        People p1 = new People();
        p1.name = "java";
        p1.sex = "nan";
        p1.age = 50;
        p1.show();
    }
}

运行结果
在这里插入图片描述
还有一种就是在定义成员变量的时候赋值,但并不建议这样写,因为在实例化后还是能初始化,没必要多此一举。而且这个类是一个模板,把模板初始化也是不合适的。

class People{
    //成员变量/字段/属性
    public String name = "zhangsan" ;
    public String sex = "lisi";
    public int age = 22;
    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
}

再来看一个代码,这个代码是什么意思呢?

public static void main(String[] args) {
        People p1 = new People();
        People p2 = p1;
}

在这里插入图片描述

这段代码的意思是 p2这个引用,引用了p1指向的这个对象

还有一个问题,一个类可以同时指向多个对象吗?

public static void main(String[] args) {
        People p = new People();
        p = new People();
        p = new People();
}

答案是不能,这里的p只会指向最后一个对象,前面的都被覆盖掉了。

所以一个引用只能同时指向一个对象

2.方法

就是我们曾经讲过的方法,用于描述一个对象的行为.

上面我们已经介绍过了,这里就是一个显示人的信息的方法。
这样的 show 方法是和 p 实例相关联的. 如果创建了其他实例, 那么 show 的行为就会发生变化

class People{
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;
    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
    public void prt(){
        System.out.println("爱java");
    }
}
public class Test {
    public static void main(String[] args) {
        People p1 = new People();
        p1.show();
        p1.prt();
    }
}

运行结果

在这里插入图片描述

成员方法也是通过 对象访问的!

3.toString方法

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


class People{
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;
    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }
}
public class Test {
    public static void main(String[] args) {
        People p1 = new People();
        System.out.println(p1);
    }
}

运行结果
在这里插入图片描述

我们发现这里打印的是一个地址,这里在打印的时候会默认调用Object 的 toString 方法来打印

在这里插入图片描述
默认调用Object 的 toString 方法,但是当前类如果重新实现 toString 这个方法后,就会调用当前类重新写的这个toString方法来打印。

IDEA快速生成Object的toString方法快捷键:alt+insert

在这里插入图片描述
再来看一段从写toString方法后的代码

class People{
    //成员变量/字段/属性
    public String name ;
    public String sex;
    public int age;
    //成员方法/行为
    public void show(){
        System.out.println("姓名:"+name+"性别:"+sex+"年龄:"+age);
    }

    @Override//重写toString
    public String toString() {
        return "People{" +
                "name='" + name + '\\'' +
                ", sex='" + sex + '\\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        People p1 = new People();
        System.out.println(p1);
    }
}

运行结果
在这里插入图片描述
我们发现当我们重写toString方法后打印的就是我们重写的toString方法里的内容。
当然重写里双引号里面的内容是可以修改的

@Override
    public String toString() {
        return "People{" +
                "姓名='" + name + "," +
                ", 性别='" + sex + '\\'' +
                ", 年龄=" + age +
                '}';
    }

注意: 所以当我们没有重写toString方法的时候,就会默认调用Object 的 toString 方法来打印

@Override 在 Java 中称为 “注解”, 此处的 @Override 表示下面实现的 toString方法是重写了父类的方法.

(1)序列化和反序列化

序列化:把一个对象变成字符串
反序列化:把字符串变成对像

4.匿名对象

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

用法如下

public class Test {
    public static void main(String[] args) {
        new People().name = "李四";
        new People().sex = "男";
        new People().age = 18;
        new People().show();

    }
}

每使用一次就得 new 一次

四、static 关键字

1.静态成员变量

我们成员变量分为 普通成员变量和静态成员变量
普通成员变量也叫做实例得成员变量,静态成员变量也叫做类变量。

我们来看下这段代码,我们用 static 关建键字创建了一个静态成员变量cont,我分别用引用和类名来访问 cont ,发现通过对象来访问得时候编译器给了一个警告。
在这里插入图片描述
运行结果

在这里插入图片描述
运行发现并没有报错,但对于整体的一个规范我们还是建议用 类名来访问静态成员变量。

所以静态成员变量的访问方式为 类名.静态成员变量

(1) 静态成员变量在内存中的存储

来看一个代码:

class People{

    public String name ;
    public int age;//普通成员变量

    public static int cont;//静态成员变量
}
public class Test {
    public static void main(String[] args) {
        People p = new People();
        p.age++;
        People.cont++;
        System.out.println(p.age);
        System.out.println(People.cont);

        People p2 = new People();
        p2.age++;
        People.cont++;
        System.out.println(p.age);
        System.out.println(People.cont);

    }
}

运行结果
在这里插入图片描述

我们发现 age和cont的区别就是一个没有被 static修饰,一个被static 修饰,那是不是这cont就是同一个cont呢?
在这里插入图片描述
静态成员变量是存在方法区,所以它的访问是不依赖于对象的。
让我们再来看一个例子

class People{
    public String name ;
    public int age;//普通成员变量
    public static int cont;//静态成员变量
}
public class Test {
    public static void main(String[] args) {
        People.cont++;
        System.out.println(People.cont);
    }
}

运行结果
在这里插入图片描述
和普通成员变量不同的是这里我们并没有实例化一个对象,直接通过类名来访问了cont,而普通成员变量不实例化是会报错的。
同样来看这个例子,这段代码运行会报错吗?

class People{
    public String name ;
    public int age;//普通成员变量
    public static int cont;//静态成员变量
}
public class Test {
    public static void main(String[] args) {
        People p = null;
        System.out.println(p.cont);
    }
}

运行结果
在这里插入图片描述
这是为什么呢?我们前面说过 null.任何东西都会出现空引用异常,那这里为什么没有呢?
这里的 p代表p不指向任何对象,而我们已经说过静态成员变量的访问时不依赖于对象的,所以这里并没有发生异常。但如果通过 p访问普通成员变量的话就会报错。
总结:

1.静态成员变量的访问方式是 类名.静态成员变量
2.静态成员变量是不依赖于对象的。

2.静态成员方法

成员方法也分为两种,一种是普通的成员方法,一种是静态的成员方法。
普通的成员方法又叫做实例的成员方法,静态的成员方法也叫做类方法。

通过 static 关键字来创建静态成员方法,且也是通过 类名来访问的

class People{
    public String name ;
    public int age;//普通成员变量
    public static int cont;//静态成员变量

    public static void prt(){
        System.out.println("这是一个静态的成员方法");
    }
}
public class Test {
    public static void main(String[] args) {
        People.prt();

    }
}

运行结果:
在这里插入图片描述
再来看一个例子:
为什么在普通成员方法里访问普通成员变量不报错,而在静态成员方法就报错呢?
在这里插入图片描述

因为静态的成员方法是通过类名来调用的,此时并没有示例化一个对象,我们知道普通的成员变量必须实例化对象后才能使用。
而在普通的成员方法里就可以访问是因为如果想调用普通成员方法就必须实例化对象,实例化对象后这里的 age和name都产生了,所以可以访问

同理可推到出,在静态的成员方法内部也是不可以调用普通成员方法的
在这里插入图片描述

所以在静态的成员方法内是不可以访问普通的成员变量的,也不能调用普通成员方法
注意:我们曾经写的方法为了简单, 都统一加上了 static. 但实际上一个方法具体要不要带 static, 都需要是情形而定.
静态的在类加载的时候就已经定义好了,具体在后面的JVM中会讲解到。

再来看一个final修饰的成员变量,这里的存储和final没关系,主要还是看static修饰。
在这里插入图片描述

五、封装

OOP 语言:面向对象编程,有一些重要的特征:继承 封装 多态
封装:在我们写代码的时候经常会涉及两种角色: 类的实现者类的调用者

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

举个例子:
我把类里的name和age都改一下

class People{
    public String name ;
    public int age;//普通成员变量
    public static int cont;//静态成员变量

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\\'' +
                ", age=" + age +
                '}';
    }
}
public class Test {
    public static void main(String[] args) {
        People p = new People();
        p.name = "张三";
        p.age = 18;

    }
}

那类的调用者调用这个类的时候发现这个类被修改,那么它就要大量修改代码。所以 这样的代码非常不安全。
在这里插入图片描述
为了避免这样的情况就得使用封装

1.private实现封装

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

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

这里我用private修饰了name,它只能在当前类里使用
在这里插入图片描述

2. getter和setter方法

当我们用private修饰字段后,这个字段就无法被直接使用了。
这个时候就用到了 getset 方法了

class People{
    private String name ;
    private int age;//普通成员变量
    public static int cont;//静态成员变量

    public void setName(String myName){
        name = myName;
    }
    public String getName(){
        return name;
    }
    public  void setAge零基础学java-类和对象

java类和对象详解

Java 基础语法爆肝1W字只为弄懂类和对象

JAVA---抽象类和接口基础知识详解(及两者异同点)

Java基础(basis)-----抽象类和接口详解

大数据必学Java基础(四十六):内部类和面向对象项目实战