Java面向对象(初级)笔记整理/图解快速回顾/图解快速入门(一)

目录

一、类和对象

1、为什么要有类和对象?

2、举例

3、如何创建一个对象?

4、如何访问对象属性以及方法?

5、总结

二、类和对象在内存中的存在形式(重要)

1、运行Cat cat = new Cat();

2、cat.age = 3; cat.name = "小白";

3、什么是一个新的对象?

4、为什么要了解这个内存机制?

三、方法的调用机制(重要)

四、方法的使用细节

1、使用有参数的方法时,要传入对应的或者相兼容的参数

2、方法想要返回多个值,则可以返回数组。

3、返回类型可以是任意类型,包括数组,和对象

4、方法内不能定义方法

5、同一个类中的方法可以直接调用

6、不同类的方法需要先创建对象再使用

五、方法的传参机制(重要)

1、基本数据的传递

2、引用类型数据的传递

3、小结

六、方法的重载

1、什么是方法的重载?

2、重载注意事项

七、可变参数

1、如何使用可变参数?

2、可变参数注意事项

八、参数的作用域

1、属性/全局变量

2、局部变量

3、全局变量 局部变量使用细节

(1)默认值

(2)同名变量的就近原则

(3)修饰符

九、构造器

1、使用构造器

2、构造器使用细节

(1)我们新建一个类时,这个类的内部是自带一个隐藏的无参构造器的。

(2)当我们自己定义一个有参构造器时,类自带的无参构造器会自动清除,此时如果想再使用无参构造器,就要显式的自己重新定义一下。

(3)创建对象时,自动调用构造器中的方法

(4)构造器完成的是对象的初始化,并不是创建对象。

十、this关键字

1、this的作用

2、 this在内存中的存在形式

3、this的使用细节


一、类和对象

1、为什么要有类和对象?

为了便于Java程序的管理,Java采用面向对象的编程思想(OOP)。

2、举例

现在有一个小猫(名字叫小白),我想用Java程序描述这个猫,就要用到类和对象。

class Cat{
    int age;
    String name;
}

如代码所示,这里我创建了一个Cat类,也就是创建了一个数据类型,就像int double String。Cat类里面有两个属性,age年龄和name名字。

这里的Cat类,就有了所有的猫共有的属性(年龄 ,名字)。

我们还可以定义猫的一些行为,这就是类中的方法

如:

class Cat{
    int age;
    String name;
    
    public void mew(){
        System.out.println("喵喵叫~");
    }
}

这里我定义了一个mew()方法,表示小猫叫的行为

3、如何创建一个对象?

以上我定义的这些,都只是猫这个类,并不是某一个具体的对象。

我们需要将类实例化,才能创造出一个对象。

如:

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
    }
}

这里我在主方法中创建了一个猫的对象。(new了一个对象)

Cat cat = new Cat();

这就相当于一个小猫的诞生。

我们还可以给它名字以及年龄(属性赋值),还可以控制小猫的行为(使用方法)。

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.age = 3;
        cat.name = "小白";
        cat.mew();
    }
}

这里我让它的年龄(age)为3,名字(name)为“小白”,然后使用它的mew()方法,来让它喵喵叫,输出:

4、如何访问对象属性以及方法?

使用“.”这个符号,就能访问一个对象的属性,或者使用其方法(这里还有访问修饰符的问题,后面说)。

比如,我想要知道这个小猫对象的名字,或者年龄,可以这样:

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.age = 3;
        cat.name = "小白";
        cat.mew();

        System.out.println(cat.name + cat.age);
    }
}

使用System.out.println()然后用".'这个符号将cat.name和cat.age输入进去就可以了。

输出: 小白3

5、总结

可以见得,使用类和对象来管理Java中的内容,是非常方便的,只要定义一个类,并且创建对象,给每个不同的对象赋值就能管理很多内容。

这里需要注意,一个类不是一个对象。

就像我们都是人类,但是我们每一个人都是一个独立的对象(小明、小红)。

二、类和对象在内存中的存在形式(重要)

1、运行Cat cat = new Cat();

我们通过这条语句来认识类和对象在内存中的存在形式

这是我们java虚拟机的内存,大致分为三块,栈、堆、方法区(至于什么是栈、堆......以后再说,现在先知道就是两块不同区域)。

当我们创建一个对象时,内存里发生了什么事呢?

当我们创建一个对象,也就是

执行

Cat cat = new Cat(); 

这条语句时

内存中的堆里,会开辟这样一个空间:

这个空间有一个地址,我们假定是0x1111,这个空间,其实就是我们创建出来的对象本体

这个空间里还有我们在Cat类中定义的属性,name、age,但是现在由于我们没有给定一个值,所以name和age在内存中都是默认值。

name 是 String类型,所以默认值为null;而age是int类型,所以默认是0;

此时,这条语句:
Cat cat = new Cat(); 
还没有执行完毕。

以上其实只是new Cat();这一步的操作。

而“Cat cat = ”还没有完成。

内存创建一个真正的对象空间以后,会在栈中创建一个cat 并设置一个地址,指向我们真正的对象。这也就是我们"Cat cat =" 的操作。" = "就是指向这个对象。

正是因为cat在内存中指向了0x1111这个真正的对象空间,我们才可以在代码中使用cat来当做我们新创建的这个对象。

cat作为对象

至此,"Cat cat = new Cat();"就运行完毕。

2、cat.age = 3; cat.name = "小白";

运行这条语句内存会发生什么变化呢?

对于age属性,我们定义的是int类型,在对象空间中,cat.age = 3;

我们会直接将3放在对象空间中的age区中,如图:

而执行cat.name = "小白"这条时,

由于name属性我们定义的是String类型,所以与int属性的处理有所区别。

Java程序会先在方法区中的常量池中(常量池是方法区中的一块小区域)查找是否有“小白”这个字符串,

显然是没有的,所以程序会在内存中创建一个“小白”字符串,这个“小白”有一个地址,我们假定是0x22

创建完成后,就会将name指向这个"小白"(即让name存储0x22这个地址)

这样,我们这个cat对象的name就是“小白”了。

3、什么是一个新的对象?

Cat cat1 = null;
cat1 = cat;

刚才我们创建了一个对象cat,现在我声明一个新的Cat—— cat1,先让其初始化为null,

然后再让其指向cat。

问题:cat1是一个新的对象吗?

答:不是。

它在内存中是这样的。

之前我提到 堆中的这个空间才是真正的对象 从图中可以看到,cat和cat1都只是指向了这同一个对象,所以,cat和cat1是同一个对象,cat1不是一个新对象。

4、为什么要了解这个内存机制?

不了解内存机制的话,会造成很多程序设计上的混乱。

看一下这个题:

如果不了解对象在内存中的机制,可能就会产生这样的疑惑:

我明明修改的是a.name为小明,为什么b.name也变成了小明?

我明明修改的是b.age为200,为什么a.age也变成了200?

我们学习了内存中的运行机制后,答案现在就显而易见了,因为a和b指向的是同一个对象,

所以不管是a修改还是b修改属性,都是内存中那个同一个对象在修改。

三、方法的调用机制(重要)

同样的,我们还要了解一个对象的方法(成员方法)的机制。

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.age = 3;
        cat.name = "小白";

        //下面调用了cat的成员方法
        cat.mew();
    }
}

如图,我们在主方法中调用了cat对象的方法mew(),在内存中是这样调用的:

在栈中存在着主方法,以及其中的各行代码

当执行到cat.mew()这行时,栈中会出现一个新的空间:

当mew方法执行完毕后,这个方法就会被栈弹出(更具体的内容见数据结构),在方法区中消失。

然后回到main方法中继续执行没执行完的内容。

需要注意这里的mew方法没有返回值,如果成员方法有返回值,也是一样的,只不过多一个返回值到main方法中继续执行。

四、方法的使用细节

1、使用有参数的方法时,要传入对应的或者相兼容的参数

这里创建一个A1类,内有一个方法sum用于返回两个参数的和,如图

public class Example02 {
    public static void main(String[] args) {
        A1 a1 = new A1();
        System.out.println(a1.sum(1, 2));
    }
}

class A1{
    public int sum(int a,int b){
        return a + b;
    }
}

输出:

这里传入的1,2都是int类型,如果我传入double类型会怎样?

报错了,编译器不允许通过。

就是说:如果需要int型参数,就不能传入double等更高精度的变量

而反过来是可以的:

所以,方法传入的参数可以是较低精度的参数,而不能是较高精度的参数。

2、方法想要返回多个值,则可以返回数组。

3、返回类型可以是任意类型,包括数组,和对象

4、方法内不能定义方法

5、同一个类中的方法可以直接调用

如图,这里定义了一个getAge方法,我们可以将mew方法改为图中内容

class Cat{
    int age;
    String name;

    public void mew(){
        System.out.println("喵喵叫~ " + "我今年" + getAge() + "岁");
    }

    public int getAge(){
        return age;
    }
}

输出:

可见,本类的方法可以在本类中直接使用。

6、不同类的方法需要先创建对象再使用

如图 我们的主类Example01和Cat类是不同类,所以要使用Cat类的mew方法则需要先创建一个对象再用对象名 + “.”调用方法。(还有一个特殊情况,static静态方法,用类名+“.”调用 这篇不提)

而跨类调用方法还与访问修饰符有关,后面说。

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.age = 3;
        cat.name = "小白";
        cat.mew();
    }
}

五、方法的传参机制(重要)

1、基本数据的传递

public class Example03 {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        swap(a,b);
    }

    public static void swap(int a, int b) {
        //这个方法的作用是交换a b的值
        int t;
        t = a;
        a = b;
        b = t;
    }
}

这里我写了一个交换a b的值的方法,在调用swap()方法后,你能说出a b的值分别是多少吗?

我们先看在内存中是怎样运行的:

刚刚说过方法调用的机制,可以看到,当执行到swap方法这一行时,会在栈中新开一个空间

而我们的这几行代码:

public static void swap(int a, int b) {
        //这个方法的作用是交换a b的值
        int t;
        t = a;
        a = b;
        b = t;
    }

则是在这个新开辟的栈空间里执行:

可见,main方法中的a、 b将参数传递给了swap方法空间中的a、b,注意,这两个a、b是在不同的空间的,也就是说,虽然swap方法中和main方法中的两个a的值都是1,但是它们不占有同一个空间,本质上不是一个a。让我们看看接下来会怎样:

swap方法中的a b的值交换,交换过后,swap的方法执行结束,按照我刚刚所说的,swap方法会被栈弹出,从此不复存在:

而我们可以看到,这个交换的过程,跟main方法的a和b是完全没有关系的,所以这个swap方法,交换的参数只是swap方法空间中的形式参数而已,与main方法的a b完全无关。

所以最终main方法中的a b的值,并没有变化。

2、引用类型数据的传递

public class Example04 {
    public static void main(String[] args) {
        B01 b01 = new B01();
        int[] arr = {1,2,3};
        System.out.print("更改前 arr = ");
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i]);
        }
        b01.changeArr(arr);
        System.out.println();
        System.out.print("更改后 arr = ");
        for (int i = 0; i < arr.length; i++) {
            System.out.print( + arr[i]);
        }

    }
}

class B01 {
    //在B01类中定义方法,作用是将数组中第一个元素和第二个元素交换
    public void changeArr(int[] arr) {
        int t;
        t = arr[0];
        arr[0] = arr[1];
        arr[1] = t;
    }
}

如图我定义了一段代码,我在B01类中定义方法changeArr(),作用是将数组中第一个元素和第二个元素交换。

在主方法中 我定义一个数组arr = {1,2,3}   并对这个arr数组使用这个changeArr()方法。

请问最后我打印出来的arr数组是{1,2,3}不变,还是{2,1,3}成功交换了呢?

答案是{2,1,3}成功交换了。

因为数组数据是引用类型,就像之前的cat和cat1一样,是通过地址,指向同一个内存区域。

所以更改的时候即便会新开一个栈空间,也会直接将其指向的内存区域进行更改。

如图所示,arr[ ]数组创建了以后,会在堆中开辟一个空间(假定地址是0x1133),这个空间就存放着arr[ ]数组的值。

而我们的arr则指的就是这个地址0x1133,所以我们在传参数给changeArr()方法时,传入的就是堆中数组空间的地址,所以在更改的时候,改变的就是堆中真正的数组空间的数据,也就是会实际影响到真正的数据。

3、小结

new了一个新对象,就是在堆中开辟一个新的对象空间,如果只是单纯的让cat1 = cat,这并不是创建了一个新的对象。

而对于参数而言,一定要确定其类型是否是引用类型。这样才能准确的判断参数的实质改变。

六、方法的重载

(这里跳过了方法递归的内容,留到数据结构与算法再聊)

1、什么是方法的重载?

如图这两个方法就构成了方法的重载:

在同一个类中两个sum方法的传入的参数不同,会构成方法重载,这避免了给众多的方法起名字的麻烦。(就不用再取名叫sum1、sum2……直接统一用sum即可)

2、重载注意事项

(1)方法名必须相同,才能构成重载。

(2)形参列表中参数的类型、顺序、数量,这三者必须有一个及以上个不同,才能构成重载。

(3)重载对于返回类型没有要求,如果只有返回类型不同,也不能构成重载。

七、可变参数

在方法中可能添加一个或者多个同类型参数时使用

1、如何使用可变参数?

如图所示:

在这个地方,可变参数的意思就是,可以往这个方法中传递任意多个int型变量,来进行相加。

可以这样一个一个输入,也可以使用数组的形式传递进去。

输出结果都是:

2、可变参数注意事项

(1)可变参数在方法的形参列表中,必须排在最后一个,不然会报错:

(2)在同一个方法中不可以有多个可变参数,只能有一个。

(3)在使用可变参数的时候当做数组来处理即可

(使用for循环处理数组相加)

八、参数的作用域

参数的生死存亡

1、属性/全局变量

如图,在这段代码中定义了一个A04类,内有一个属性i,初始化为1,它的作用范围就是整个类的代码块中。

例如:这里我创建一个方法,让i = 10;这时的i就是类中的属性i,说明只要在这个类中,无论是在这个类中,还是在这个类的方法中,类中的属性都可以使用,因此类的属性也叫全局变量。

2、局部变量

局部变量指在方法或者代码块(代码块的内容以后再聊)中定义的变量。

它的作用范围就是其定义的方法或代码块内部。

例如:我在A04类中创建一个方法,再在方法中定义一些变量,这些变量就都是局部变量

现在我在这个方法外,试图访问方法内的局部变量,

编译器报错,无法识别,这就是因为超过了其作用域。

3、全局变量 局部变量使用细节

(1)默认值

局部变量使用时需要给定一个值,不然无法使用。

而全局变量则有默认值,不需要给定值也可以直接使用。

局部变量没有默认值,所以要先初始化一个值才可以使用。

(2)同名变量的就近原则

如果全局变量和某方法内的局部变量重名,会发生什么呢?

例如,我在这里设置一个属性i = 1;AAA方法内的局部变量 i = 2(注意,这里我是重新定义了一个i,而不是更改属性里的i的值,跟之前有区别,之前没有int 来重新定义,现在有int 是重新定义了一个局部变量i)然后打印出i的值,那么这个i打印出来的是1 还是 2呢?

遇到局部变量和属性(全局变量)同名,就要遵循就近原则

对于方法中的System.out.println(i)来说,必然是局部变量i更近一些,所以打印出来的也就是2。

结果:

这个就近原则的“近”不是字面意思上的近,例如:

这看似System.out.println(i)这条输出i的语句,距离属性i = 1更近一些,但实际上它们隔着一个方法的大括号的厚障壁,所以还是局部变量i = 2会被打印出来。

(3)修饰符

局部变量不可以加访问修饰符,而属性/全局变量可以加访问修饰符

九、构造器

便于在创建对象时就可以初始化对象

1、使用构造器

如图中代码所示,Cat cat = new Cat();这个地方的Cat()其实就是使用了一个构造器,只不过是一个无参构造器:

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat();
    }
}

class Cat{
    int age;
    String name;

   
}

我们也可以自己定义一个构造器。如:

构造器的最开头是一个访问修饰符,然后是类名,最后是参数列表,跟方法不同的地方在于它没有返回值。(名字也必须与类名保持一致)

这是我们定义的一个有参构造器,可以将你传入的age name 直接放到创建的对象cat中的属性 age name中:

public class Example01 {
    public static void main(String[] args) {
        Cat cat = new Cat(3, "小白");
    }
}

class Cat{
    int age;
    String name;

    public Cat(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

这样我们通过这条语句:Cat cat = new Cat(3, "小白");

直接将3和“小白”按顺序带入即可在创建对象的时候初始化对象,

就可以让对象cat的age = 3,name = “小白”。非常方便。

2、构造器使用细节

(1)我们新建一个类时,这个类的内部是自带一个隐藏的无参构造器的。

这也是为什么我们没有自己定义构造器的时候,也可以使用无参构造器来创建对象。

(2)当我们自己定义一个有参构造器时,类自带的无参构造器会自动清除,此时如果想再使用无参构造器,就要显式的自己重新定义一下。

(是的,构造器也可以有多个,构造器的重载)

例如:

我们重新定义一下无参构造器:

(3)创建对象时,自动调用构造器中的方法

在这里我在无参构造器中写一个方法,来证明:

使用无参构造器创建cat对象:

结果:

所以可见

创建对象时,会自动调用构造器中的方法。

(4)构造器完成的是对象的初始化,并不是创建对象。

如图所示,构造器只是在对象创建之后,将其中的属性赋予相应的值,并不参与对象创建(对象空间在堆中的空间开辟)这个过程本身。

十、this关键字

this就是这个对象本身

1、this的作用

在使用有参构造器时,可以看到this关键字:

我们可以看到形参列表里的age和Cat的属性age是重名的,为了让编译器明白到底age是哪个age,我们用this关键字 + “.” + age 来代表这是对象的属性age。其中this就是对象本身。

所以对于cat对象而言,cat.age和this.age其实就是一回事。

对于cat对象,this.age 等价于 cat.age

2、 this在内存中的存在形式

跟属性一样,在堆中的对象本体中存储,this中存储的就是对象本身的地址,如图:

可见,this.age 和cat.age 对于cat而言是等价的,因为指向的都是同一个对象。

只不过this是对象创建时就自带的。

3、this的使用细节

this只能在类的方法中使用,不能在类的外部使用。

(显然,如果在main方法中使用this,那谁知道this是cat还是dog呢?所以只能在Cat类或者Dog类的定义内部使用)


就先整理这些吧。废了蛮多功夫的,参考了一些资料,希望对各位有帮助!

后续会继续更新面向对象的笔记,还请持续关注!

  • 28
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值