Java面向对象解析(封装、static、代码块)

前言

  • 类:类是一个模板,它是描述一类对象的属性和行为。
  • 对象:对象是类的一个实例,有属性和行为。例如:一只猫是一个对象,它的属性有:名字、颜色、品种;行为有:抓老鼠、喵喵叫、吃饭等。

下图中汽车(class),具体的每辆车为汽车类的对象(object),对象包含了汽车的颜色和品种等。

Class&Object

面向对象

  • Java是一门纯面向对象的语言(Object Oriented Program)。
  • 面相对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。

面向对象和面向过程

面向过程

面向过程注重的是操作过程中的因果逻辑。

例如:上学

Imgur

  • 面向过程中我们需要去研究公交车的一系列运行活动,还要去考虑路上发生的各种状况之间的因果关系。

面向对象

面向对象注重的是对象和对象之间的交互。

例如:上学

Imgur

  • 面向对象我们只需要关注人乘坐公交车对象到达学校,至于公交车如何运行我们不需要关注。

Java中类的定义

  • Java中使用关键字class来定义类。
public class Cat {
    String name; // 名字
    String color; // 毛色
    int age; // 年龄
    String breed; // 品种
    
    void eat() {
        System.out.println("吃饭");
    }
    void sleep() {
        System.out.println("睡觉");
    }
    void play() {
        System.out.println("玩耍");
    }
    void catchMouse() {
        System.out.println("抓老鼠");
    }
}

一个类中可以包含以下变量类型:

  • **局部变量:**在方法中定义。变量的声明和初始化都在方法内,方法结束,变量自动销毁。
  • **成员变量:**在方法外,类的内部定义。成员变量在创建对象时实例化,每个对象有单独属于自己的成员变量。成员变量可以被类中的方法、构造方法和特定类的语句块访问。
  • 类变量:声明在类的内部,方法的外部,必须是被static修饰。

一个类可以拥有多个方法。

类的实例化

类就相当于一种新的自定义类型,和Java中的基本数据类型(intdouble)相似,而创建这种自定义类型对象,我们称为实例化。

  • Java中使用关键字new来实例化对象。
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.name = "黑旗";
        c.age = 3;
        c.breed = "奶牛猫";
        c.color = "黑色";
        c.eat();
        c.catchMouse();
    }
}
  • 如上述代码所示,通过实例化的对象c来调用成员变量,给成员变量赋值,也可以调用其成员方法。

构造方法

  • Java中,创建对象至少要调用一个构造方法,我们在实例化Cat对象时,new Cat()就是在调用public Cat(){}构造方法。但显然我们并没有写任何构造方法,Java会自动帮我们生成一个无任何参数的构造方法。
public class Cat {
    public Cat() {
        System.out.println("没有参数的构造方法");
    }
}
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat();
    }
}
// 输出结果:
// 没有参数的构造方法
  • 由此可以得出结论,当我们自己写了无任何参数的构造方法,Java就会调用我们自己写的构造方法来实例化对象。
public class Cat {  
    public Cat(String name) {
        System.out.println("带一个参数的构造方法");
    }
}
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat();
    }
}
// 输出结果:
// java: 无法将类 com.max.classes.Cat中的构造器 Cat应用到给定类型;
//  需要: java.lang.String
//  找到: 没有参数
//  原因: 实际参数列表和形式参数列表长度不同
  • 如上述代码可见,当我们提供带有一个参数的构造方法,但是向通过不带参数的构造方法实例化对象时,编译是不能通过的,因为当我们提供一个构造方法时,编译器就不会再为我们提供默认的构造方法了,我们只能调用自己编写的特定构造方法来实例化对象。
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat("小花");
    }
}
// 输出结果:
// 带一个参数的构造方法

构造方法的特性

  1. 名字必须和类名相同。
  2. 没有返回值,也不能设置为void
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次。
  4. 构造方法可以重载。
  5. 如果没有显示定义,编译器会生成默认的构造方法,而且一定是无参数的。
  6. 构造方法中,可以通过this调用其他构造方法来简化代码。
    • 注:this()必须是构造方法中的第一条语句。
    • 不能形成环。
public class Cat {
  	public Cat() {
        this("小花", "花色", 2, "三花猫");
    }
    public Cat(String name, String color, int age, String breed) {
        name = name;
        color = color;
        age = age;
        breed = breed;
    }
}
  1. 绝大多数情况下,使用public进行修饰,特殊场景下会被private修饰。

this引用

  • 构造方法可以帮助我们在实例化对象时,就对对象的成员变量赋值。但若带有参数的构造方法中的形式参数名和成员变量名相同时:
public class Cat {
    public Cat(String name, String color, int age, String breed) {
        name = name;
        color = color;
        age = age;
        breed = breed;
    }
}
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat("小花", "花色", 2, "三花猫");
        System.out.println(c.name + " " + c.color + " " + c.age + " " + c.breed);
    }
}
// 输出结果:
// null null 0 null
  • 由于局部变量优先原则,构造方法中并没有成员变量,因此并没有对成员变量赋值。这就需要this引用来帮我们区分成员变量和局部变量。

实际上,在类内部的方法中,都有一个隐藏的形参,编译器为我们提供的对象的引用。

public Cat(Cat this, String name, String color, int age, String breed) {}

这个Cat this就是编译为我们提供的,指代当前的对象。

  • 因此我们构造方法就可以写成一下样式:
public class Cat {
    public Cat(String name, String color, int age, String breed) {
        this.name = name;
        this.color = color;
        this.age = age;
        this.breed = breed;
    }
}
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat("小花", "花色", 2, "三花猫");
        System.out.println(c.name + " " + c.color + " " + c.age + " " + c.breed);
    }
}
// 输出结果:
// 小花 花色 2 三花猫

Imgur

Imgur

  • 通过调试我们也可以看出this和对象c地址相同,说明this就是该对象。

this引用的特性

  1. this只能在成员方法中使用。
  2. 在成员方法中,this只能引用当前对象,不能再引用其他对象。
  3. this是成员方法第一个隐藏的参数,编译器会自动传递。

默认初始化

public static void main(String[] args) {
    int a;
    System.out.println(a);
}
// error:java: 可能尚未初始化变量a
  • 当局部变量声明,但未初始化和赋值时,编译会报错。但我们发现成员变量未赋值时,编译器不会报错,我们照常可以使用该成员变量,这是因为编译器会自动对成员变量赋初始值。如下表所示:
数据类型默认值
byte0
short0
int0
long0L
float0.0f
double0.0
booleanfalse
char‘\u0000’
引用数据类型null

封装

面向对象三大特性:封装、继承、多态。

  • 封装就是隐藏细节。例如我们的手机,我们在不拆开手机的情况下是无法看到主板的;再比如电视,电视的一系列程序我们是不知道的,我们只需要使用遥控器就可以操作电视。这就是程序员对程序进行了封装,只提供特定的接口来供使用者使用,以保证程序不被破坏。

访问修饰限定符

  • 在我们最开始学习Java,接触的第一个方法main方法,就会看到有public关键字,这就是访问修饰限定符。
  • Java中一共有四种访问修饰限定符:
    • private:私有的。
    • default:默认的,什么都不写时的默认权限。
    • protected:受保护的。
    • public:公有的。
序号范围privatedefaultprotectedpublic
1同一包中的同一类
2同一包中的不同类
3不同包中的子类
4不同包中的非子类

包的概念

为了更好的管理类,把多个类放在一组,称为软件包。

在同一个工程中,允许存在相同名称的类,只要处于不同的包中即可。

导入包中的类

Java中提供了很多现成的类供我们使用,如Date类,它在java.util这个包下,我们要想使用,就需要导入这个包。

  1. 使用包名+类实例化对象。
java.util.Date date = new java.util.Date();
  1. 使用import导入包。
import java.util.Date;
Date date = new Date();

static成员

当我们创建中国人这个类时,除了名字、年龄、身份证号等属性外,还应该有国籍这个属性。但既然是中国人,国籍一定是中国,这就没有必要让每一个对象都单独有一份数据,只需要把国籍这个属性变成类的属性即可。

static修饰成员变量

  • static修饰成员变量,称为静态成员变量/类变量,它不再属于某个具体的对象,而是所有对象共享的,是属于类的。
public class ChinaPerson {
    private String name;
    private int age;
    private String id;
    public static String nation = "中国";
}
public class ChinaPersonTest {
    public static void main(String[] args) {
        ChinaPerson chinaPerson1 = new ChinaPerson();
        ChinaPerson chinaPerson2 = new ChinaPerson();
        ChinaPerson chinaPerson3 = new ChinaPerson();
        ChinaPerson chinaPerson4 = new ChinaPerson();
        ChinaPerson chinaPerson5 = new ChinaPerson();
        System.out.println();
    }
}

Imgur

如图可知,对象中没有nation这个属性,说明nation不再属于对象。

System.out.println(ChinaPerson.nation); //输出:中国
  • 静态成员变量/类变量通过类名.的方式调用

特性

  1. 不属于某个具体的对象,是类的属性,所有对象共享,不存储在某个对象的空间中。
  2. 既可以通过对象访问,也可以通过类名访问,但一般推荐使用类名访问。
  3. 类变量存储在方法区中。
  4. 随类的加载而创建,随类的卸载而销毁。

static修饰成员方法

  • 当我们将静态成员变量用private修饰,就不能在该类外访问该变量,因此我们需要提供接口来访问修改它。
  • 静态成员变量一般通过静态成员方法来访问。
private static String nation = "中国";

public static String getNation() {
    return nation;
}

public static void setNation(String nation) {
    ChinaPerson.nation = nation;
}

特性

  1. 静态成员方法不能访问成员变量,因为静态成员方法属于类方法,不需要创建对象就可以访问,因此没有对象概念。

Imgur

  1. 静态方法中不能调用非静态方法,原因如上。
  2. 可以通过对象调用,也可以通过类名调用,更推荐使用类名调用。
  3. 不属于某一个具体的对象,而是属于这个类的方法。

代码块

{}定义的一段代码就称为代码块。根据定义的位置和关键字,可分为四种:

  • 普通代码块
  • 构造代码块
  • 静态代码块
  • 同步代码块

普通代码块

  • 普通代码块:定义带方法中的代码块。
public class Test {
    public static void main(String[] args) {
        {// 普通代码块
            int x = 20;
            System.out.println(x);
        }
        int x = 10;
        System.out.println(x);
    }
}

构造代码块

  • 构造代码块:也叫实例代码块,一般用于初始化成员变量。
public class Cat {
    private String name; // 名字
    String color; // 毛色
    protected int age; // 年龄
    public String breed; // 品种

    {
        System.out.println("这是一个构造代码块");
        name = "小花";
        color = "花色";
        age = 2;
        breed = "三花猫";
    }

    public Cat() {
    }

    public Cat(String name, String color, int age, String breed) {
        this.name = name;
        this.color = color;
        this.age = age;
        this.breed = breed;
    }
}
public class CatTest {
    public static void main(String[] args) {
        Cat c1 = new Cat();
        Cat c2 = new Cat();
        Cat c3 = new Cat();
        Cat c4 = new Cat();
        Cat c5 = new Cat();
    }
}
// 输出结果:
// 这是一个构造代码块
// 这是一个构造代码块
// 这是一个构造代码块
// 这是一个构造代码块
// 这是一个构造代码块
  • 由此可见,构造代码块是实例化一个对象就调用一次的。

静态代码块

  • 静态代码块:static定义的代码块,一般用于初始化静态成员变量。
public class ChinaPerson {
    private String name;
    private int age;
    private String id;
    private static String nation;
    static {
        nation = "中国";
        System.out.println("这是一个静态代码块");
    }
}
public class ChinaPersonTest {
    public static void main(String[] args) {
        ChinaPerson p1 = new ChinaPerson();
        ChinaPerson p2 = new ChinaPerson();
        ChinaPerson p3 = new ChinaPerson();
        ChinaPerson p4 = new ChinaPerson();
        ChinaPerson p5 = new ChinaPerson();
    }
}
// 输出结果:
// 这是一个静态代码块
  • 由此可见,静态代码块不管生成多少个对象,只会执行一次。
  • 静态成员变量是类的属性,因此在JVM加载类时开辟空间并初始化。
  • 如果一个类包含多个静态代码块时,在编译代码时,编译器会按照定义的先后顺序执行。
  • 实例代码块只有在创建对象时才会执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烛九_阴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值