Java类和对象

目录

前言

Java中一切皆可对象,接下来让我们来了解一下Java中类和对象的基础知识吧!😃

1. 类和对象

1.0类和对象的基本概念

拿洗衣机来举例子,类就好比图片中的产品型号、能耗等级等,这样自定义的类型,而对象就是这台洗衣机,要知道对象必须先要知道类,类包括了对象的属性和行为。

1.1类的定义

1.1.1 语法

class 类名{

属性/成员属性/成员变量

行为/成员方法

}

其中 class关键字用来定义一个类,如下图所示

一般情况下,成员变量我们一般都用public修饰,但是一个文件只有一个public 类,具体会在2.0权限处解释

当我们没有给成员变量初始化时,系统会给他们赋默认值,但如果是局部变量,就必须要初始化,不然会报错

1.2 实例化对象

就是由类指向对象的过程

其中,machine就是一个引用类型,由引用指向对象WashingMachine

而new就是开辟了个新的空间,给对象在堆上开辟了个空间,给引用在栈上开辟了空间,引用里面存着的是指向对象的地址,在实例化对象之前,类是在方法区内

一个类也可以实例化多个对象,彼此之间是互不影响的,因为是在不同的空间

1.2.1 引用

实例化对象的过程中必定会用到引用,我们可以通过引用来调用对象的成员方法和成员变量

其中,引用的名字是自己定义的,符合小驼峰定义名字的方法

我们也可以给引用开辟一个新的空间,则该引用就会指向一个新的对象,那么原来开辟的空间就会自动被系统回收

在新的对象里我们没有通过引用给成员变量赋值,则输出的是默认值

那么一个引用可以指向多个对象吗?

很显然不行,我们可以通过上面的知识知道,无论它开辟了多少空间最终指向的也只是最后一次开辟的空间,指向了最后的那一个对象

引用也可以指向null,代表着该引用不指向任何对象

由于该引用不指向任何对象,所以不可以通过引用调用对象里的成员变量和方法,会报错

引用不可以指向另一个引用,但是可以指向另一个引用指向的对象

由于machine1指向了machine所指向的对象,所以由machine1 所开辟的空间就会被系统自动回收

1.3 构造方法

1.3.1 系统默认的构造方法

当我们创建一个类时,系统会默认产生一个构造方法

方法里面什么也没有,所以我们什么都看不到,而值得我们注意的是构造方法是没有返回值的,而且方法名和类名相同

可一旦我们创建自己的构造方法,系统就不会再创建默认的构造方法了

并且我们可以通过快捷方法或者设置快捷键来创建构造方法 --

点击鼠标右键 --> 选择Generate --> 点击Constract

然后回出现这样的界面,这时按住ctrl 键就可以选择两个成员变量,最后点击ok,IDEA就会帮我们生成构造方法

这样我们就可以在实例化对象的过程中给成员变量赋值

当我们创建了构造方法时,就必须在实例化对象时传参,不然会报错,因为系统不会再帮我们创建无参数的构造方法了

1.3.2 this引用
(1) this引用成员变量

语法: this.成员变量名

细心的人会发现,上处系统IDEA帮我们生成构造方法时出现了this引用,其代表的是当前对象的引用,也就是当前是谁创建了对象this就代表着谁,实际上再每个成员方法最前面都会默认有个this

如果像这样变量名不同,不加this也没有什么错误,但如果变量名相同,不加this就会有错误了

我们会发现即使我们给成员变量赋了值,最后输出的依旧是默认值,这是由于即使我们传值过去,model也是局部变量,这是方法内会优先使用局部变量,则是自己给自己赋值,不会改变成员变量,但我们加上this结果就不一样了

这是我们发现成员变量不再是默认值了,这是由于加上this就代表当前引用指向的对象的model,和局部变量得以区分


(2) this引用成员方法

语法:this.方法名( );

这时可能会有人问:为什么不直接在main方法内部直接用this引用成员方法?

这里涉及到静态成员变量的知识,将在1.4内具体讲解,这里先知道this引用不能引用由static修饰的成员变量和成员方法


(3) this引用构造方法

语法:this( );

这表示的是在构造方法内调用另外一个构造方法,仔细观察我们会发现此处出现了重载--方法名相同,参数不同

值得注意的是,this引用构造方法只能在构造方法内使用,而且必须是放在第一行,不然会报错

更要注意避免出现循环调用的现象


1.4 成员变量和成员方法

前面一直由提到成员变量和成员方法,接下来让我们具体了解一下成员变量和成员方法吧!

1.4.1 成员变量和局部变量的区别

成员变量: 定义在类的里面,方法的外面,不用初始化,系统会自动赋值默认值

局部变量: 定义在方法内部,必须要初始化,生命周期仅限于方法内,一旦方法执行完,局部变量开辟的空间就会被系统回收


1.4.2 静态成员变量和静态成员方法

此处要用到一个关键字 -- static

被static修饰的成员变量和成员方法都是静态的,其中最常见的就是main方法

静态成员变量和静态成员方法有一个特性:不属于对象,所以不用实例化对象,直接通过类名就可以访问

大致了解了static,接下来,讲述几个静态成员变量和成员方法要注意的点

(1) 在静态方法内不能直接调用非静态成员变量和方法

最简单的就是在main方法内不能直接调用类中非静态的成员和方法,需要先实例化对象,再通过引用来调用,还是拿我们的洗衣机来举例子

我们可以很明显的看到如果直接调用会报错,可知,但凡是非静态的变量和方法都不能直接调用,需要实例化对象

(2) 静态方法内部不能使用this引用

这是由于this是与对象有关的,而静态方法不属于对象,是直属于类,直接通过类名引用,虽然实例化对象通过引用来引用静态成员变量只会报出警告,但是还是建议直接通过类名引用

可见,this报错了,main方法也被static修饰着,属于静态方法


(3) 静态方法获取成员变量

在实际操作写代码时,我们设置静态成员变量,这样就可以简化代码,直接通过类名引用赋值,直接跳过实例化对象这个步骤。

同理,也可以直接通过类名引用输出值


1.4.3 静态成员变量赋值

既然上面已经谈到了静态成员变量赋值,那么这里我们就来细说吧!

(1) 直接赋值

直接在定义变量的时候就赋值

当然我们不建议这么赋值,不过也根据自己的需求吧


(2) 默认初始化

也就是不初始化,系统默认初始化


(3) 通过get和set方法进行初始化

可以让IDEA来帮我们写代码,和1.3构造方法处的简便方法差不多

点击鼠标右键 --> 选择Generate --> 点击Getter and Setter,按住CTRL选择多个变量

IDEA会帮我们生成get和set方法


(4) 通过构造方法初始化

这也在Generate里选择Constract选择要初始化的静态成员变量

这样我们可以在实例化对象的时候赋值,不过并不推荐这种方法来初始化静态成员变量

因为这种方法是通过对象来调用静态成员变量赋值的(this代表的是当前对象的引用)

前面有说过静态成员变量和方法都是属于类的,不属于对象,故用对象调用静态成员变量会报出警告


(5) 通过代码块初始化

此处涉及到1.5代码块知识,将在1.5 处详细讲解,此处简单提出

代码如下


1.5 代码块

在Java中使用{}括起来的代码被称为代码块

代码块也分普通代码块、构造代码块/实例化代码块/非静态代码块、静态代码块、同步代码块


1.5.1 普通代码块

普通代码块在方法内出现,普通代码块内的变量是局部变量生命周期很短,且只代码块内有效,出了代码块后就被系统回收

接下来,用如下的代码块来证实

这是由于代码块内的变量是局部变量,而改变局部变量不影响成员变量的值,所以a还是系统默认值

接下来看看普通代码块的执行顺序


class Date{
    {
        System.out.println("我是普通代码块1");
    }
    {
        System.out.println("我是普通代码块2");
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
    }
}
//输出
我是普通代码块1
我是普通代码块2

可见当类内无构造方法时呕吐代码块是按顺序执行的,可若有构造方法呢?

接下来看看这串代码


class Date{

    public Date() {
        System.out.println("我是构造方法");
    }

    {
        System.out.println("我是普通代码块");
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
    }
}
//输出
我是普通代码块
我是构造方法

可见,普通代码块的执行是优先于构造方法的


1.5.2 构造代码块

其实也就是在构造方法后的代码块,可以用于初始化非静态成员变量(前提是不带参数的构造方法)

首先是无参数的构造方法


class Date{
    public int a;
    public Date() {

    }
    {
        System.out.println("构造代码块");
        a = 100;
    }
}
public class Static {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date.a);
    }
}
//输出
//构造代码块
//100

可以看到,我们可以通过构造代码块给成员变量赋值

接下来看看有参数的构造方法会输出什么


class Date{
    public int a;
    public Date(int a) {
        System.out.println("无参数的构造方法");
        this.a = a;
    }

    {
        System.out.println("构造代码块");
        a = 100;
    }
}
public class Static {
    public static void main(String[] args) {
        Date date = new Date(200);
        System.out.println(date.a);
    }
}
//输出
构造代码块
无参数的构造方法
200

从这里可以发现构造代码块执行会优先于构造方法


1.5.3 静态代码块

其实也就是加上static的代码块,可用于初始化静态成员变量(此处有在1.4.3-(5)提到过),或者提前准备一些数据


class Date{
    public static int a;
    static{
        a = 520;
    }
}
public class Static {
    public static void main(String[] args) {
        System.out.println(Date.a);
    }
}
//输出
520

接下来,我们来看看静态代码块的执行是否也优先于构造方法呢?


class Date{

    public Date() {
        System.out.println("构造方法");
    }
    static{
        System.out.println("静态代码块1");
    }
    static{
        System.out.println("静态代码块2");
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
    }
}
//输出
静态代码块1
静态代码块2
构造方法

可见,静态代码块是按循序执行的,而构造方法是最后执行的

接下来,再来看一段代码


class Date{
    {
        System.out.println("普通代码块1");
    }
    static {
        System.out.println("静态代码块1");
    }
    static {
        System.out.println("静态代码块");
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
        System.out.println("----------------");
       Date date1 = new Date();
    }
}

//输出
静态代码块1
静态代码块
普通代码块1
-------------
普通代码块1

突然发现,第二次实例化对象时并没有输出静态代码块内的内容,这说明静态代码块只执行一次


1.5.4 代码块执行顺序

看完上述内容后,可以得到无论是什么代码块的执行都优先于构造方法

那么也许会有人疑惑,如果这些代码块类都组合在一起,会是哪一中代码块会先执行呢?

接下来我们看代码


class Date{
    public Date() {
        System.out.println("构造方法");
    }
    {
        System.out.println("构造代码块1");
    }
    static {
        System.out.println("静态代码块1");
    }
    {
        System.out.println("普通代码块1");
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
        System.out.println("main方法");
    }
    static {
        System.out.println("静态代码块2");
    }
    {
        System.out.println("普通代码块2");
    }
}

//输出
静态代码块2
静态代码块1
构造代码块1
普通代码块1
构造方法
main方法

可见,静态代码块优先于所有种类的代码块,而public类内的静态代码块的执行优先于其他类的静态代码块,其次是构造代码块,再是普通代码块,然后再是构造方法,最后是main方法

即 ,静态代码块-> 构造代码块-> 普通代码块-> 构造方法-> main方法

那么这时就会有人问了:为什么普通代码块2没有执行呀?

继续看代码


class Date{

    {
        System.out.println("普通代码块1");
    }
    {
        Static sta = new Static();
    }
}
public class Static {
    public static void main(String[] args) {
       Date date = new Date();
        System.out.println("main方法");
        Static sta = new Static();
    }
    {
        System.out.println("普通代码块2");
    }
}

//输出
普通代码块1
普通代码块2
main方法
普通代码块2

可见,要在其他类或者是main方法内执行普通代码块都需要实例化对象


2. 继承 -- externds

此处简单叙述,作者无能还没有学的太深入

假设我们要定义一个狗类和猫类,那么狗和猫都一样的属性 -- 名字和年龄等,不妨把这些共性提出来,构建一个父类,让狗和猫这些子类都继承父类所有的属性。

继承:对共性进行抽取,从而实现代码的复用(需要用到关键字externds)

2.1 父类和子类

还是用上述动物的例子来写代码


class Animal{
    public String name;
    public int age;

    public void eat(){
        System.out.println(name + "正在吃饭");
    }
}
class Dog extends Animal{     //dog继承父类Animal

    public void howl(){
        System.out.println(name + " 正在汪汪叫");
    }
}
class Cat extends Animal{

    public void howl(){
        System.out.println(name + " 正在喵喵叫");
    }
}
public class inherit {
    public static void main(String[] args) {
        Dog dog = new Dog();
        System.out.println(dog.name);
        dog.eat();
        Cat cat = new Cat();
        System.out.println(cat.name);
    }
}
//输出
null
null正在吃饭
null

其中,Animal就是父类,而dog和cat就是子类

可以看到子类可以继承父类的成员变量和成员方法,输出null是因为我们还没有给成员变量赋值,所以系统提供默认值

2.2 继承中的构造方法 -- super

子类要实现构造方法时,必须先要帮父类实现构造方法

这是我们要用到关键字super -- 代表着父类的引用,可以和this类比


class Animal{
    public String name;
    public int age;
    public void eat(){
        System.out.println(name + "正在吃饭");
    }
    public Animal(String name, int age) {      //父类的构造方法
        this.name = name;
        this.age = age;
    }
}
class Dog extends Animal{
    public Dog(String name, int age) {
        super(name, age);              //子类帮助父类实现构造
    }

    public void howl(){
        System.out.println(name + " 正在汪汪叫");
    }
}
public class inherit {
    public static void main(String[] args) {
        Dog dog = new Dog("修狗",3);
        System.out.println(dog.name);
        dog.eat();
    }
}
//输出
修狗
修狗正在吃饭

其中,super();必须要在子类构造方法的第一行,而且也只能在构造方法内使用,不然会报错


3. 权限

权限:访问修饰限定符,即修改方法或者是变量的访问范围

private, default ,protected ,public


3.1 封装 -- private

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互

这就好比去银行取钱,不可能把你西汉卡的信息一下子全展现出来,需要保护你的信息,只提供你取钱的途径,所以封装提高了数据的安全性

(1) 构造方法实现封装对外的接口

利用构造方法的快捷方法


class Student{
    private String name;
    private int age;
    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void show(){
        System.out.println(this.name);
        System.out.println(this.age);
    }
}
public class Private {
    public static void main(String[] args) {
        Student student = new Student("zero",18);
        student.show();
    }
}

//输出
zero
18

如此,利用private关键字将name和age这两个成员变量封装起来,也就是改变着两个成员变量的权限,使得它们只能在类里面使用,然后利用构造方法提供对外的接口为成员变量赋值

如果在类外使用就会报错

很明显我们不可以通过引用来引用对象已经封装了的变量

(2) get和set方法实现封装对外的接口

使用get和set的快捷方法,让IDEA帮我们写代码


class Student{
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Private {
    public static void main(String[] args) {
        Student student = new Student();
        student.setAge(18);
        student.setName("zero");
        System.out.println(student.getName());
        System.out.println(student.getAge());
    }
}
//输出
zero
18


3.2 包访问权限/默认权限 -- defoult

该权限不用写出来

3.2.1包

由于是包访问权限这里简单引入包的概念

包:实际上也就是文件夹,用来整理类

包的名字一般是域名,com.开头,www结尾

例如com.zero.www

创建包

然后输入包的名字,最后可以在包里面定义类

就可以再类里面打代码了


3.2.2 包访问权限一 . 在同一个中的同一类中访问

package com.zero.www;
//声明当前类是在哪一个包底下

public class Test {
    int a = 999;

    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.a);
    }
}
//输出
999

可以看到,这是在com.zero.www包下的Test类下

default不用写出来,但是a在Test类下可以使用

3.2.3 包访问权限二 . 在同一个包中的不同类访问

接下来我再创建另外一个类 Test1 类,再来访问a


package com.zero.www;
//声明当前类是在哪一个包底下

class Test1{
    public Test1() {
        Test test = new Test();
        System.out.println(test.a);
    }
}
public class Test {
    int a = 999;
    public static void main(String[] args) {
        Test test = new Test();
        System.out.println(test.a);
        Test1 test1 = new Test1();
    }
}
//输出
999
999

可见,在同一个包中的不同类也能访问a变量


3.3 protected(保护)访问权限

protected有着default有的两个权限

3.3.1 权限一 在同一个中的同一类中访问

首先按上述操作创建一个包demo1,再在包内创建一个类Test1

输入以下代码


package demo1;

public class Test1 {

    protected static int a = 999;
    public static void main(String[] args) {
        System.out.println(a);

    }
}
//输出
999
加上static只是了方便引用,可以直接用类名引用

可见,a可以在同一个demo1当中的同一个test1类中使用


3.3.2 权限二 在同一个包中的不同类中使用

同样是在demo1包中,定义一个Test2类,在该类中使用a


package demo1;

public class Test2 {

    public static void main(String[] args) {
        System.out.println(Test1.a);
    }
}
//输出
999

可见,a在同一个demo1包中的Test2类也可以使用


3.3.3 权限三 在不同包中的子类中使用
此处就要用到上述继承的知识啦

创建另一个包demo2 ,在该包中创建一个类Test3,另Test3继承Test1


package demo2;

import demo1.Test1;

public class Test3 extends Test1 {
    public static void main(String[] args) {
        System.out.println(Test1.a);
    }
}
//输出
999

可见,demo1中Test1类中的a也可以在demo2中继承了Test1的Test3中使用


结语

以上就是Java中类和对象的基础内容啦

由于博主还处于学习阶段,希望家人们能多指导指导😘

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值