【JAVA SE】类和对象
✨✨欢迎大家来到Celia的博客✨✨
🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉
所属专栏:JAVA
个人主页:Celia's blog~
目录
编辑
一、关于面向对象
二、类的定义与使用
2.1 认识类
2.2 类的定义
2.3 类的实例化
2.4 类和对象的说明
【附加】对象在内存中的存储
2.5 类中变量以及方法的访问
三、this引用
【附加】一些建议
四、对象的构造以及初始化
4.1 构造方法
4.1.1 this的三种使用方式
五、封装
5.1 private、default、public
5.2 具体实现方法举例
六、关于static
【附加】关于加载
6.1 static修饰方法、成员变量
6.2 static修饰需要注意的事项
七、代码块
7.1 静态代码块
7.2 实例代码块
7.3 代码举例
八、对象的打印
一、关于面向对象
在我们之前的学习过程中,在写代码的时候都需要去考虑一步一步的逻辑过程,也就是面向过程去编写代码。而JAVA的主要思想是面向对象,那什么是面向对象呢?
- 我们可以想象洗衣服的过程,比如倒水、放衣服、加洗衣液、洗衣服、冲洗...等等。这一系列操作都是洗衣服的过程。
- 我们也可以使用洗衣机来洗衣服,这时,我们不需要考虑洗衣机内部是如何完成洗衣服的一系列过程,而是只需要明确把衣服放进洗衣机里,就可以达到我们的目的。
- 以上的思想就是面向对象的思想。
二、类的定义与使用
2.1 认识类
我们对于一个对象的描述一定是多角度、多方面的。比如描述一个人,就需要知道他的身高、体重、年龄、衣着等。类的作用就是把这一系列的信息统一在一起,用于描述一个对象。
2.2 类的定义
在定义类时,需要用到class关键字,具体语法如下:
//定义一个狗类 class Dog { //字段/属性/成员变量 public String Name; public int Age; //可能有一些方法... }- class为定义类的关键字,Dog是类名。
- 类中的Name与Age变量叫做字段,或者属性,或者成员变量。
- 在成员变量类型前的修饰符public暂且不用关心,后面会详细介绍。
关于类的一些注意事项:
- 一般一个文件中只定义一个类。
- main方法所在的类一般用public修饰。
- 被public修饰的类的类名必须与文件名相同。
2.3 类的实例化
一个类就像一个模板一样,比如每个人都有名字、年龄。当我们想要描述一个人时,就可以借助类这个模板来创建一个对象,这个对象中会包含类中所定义好的姓名、年龄等成员变量。
假设有以下类的定义:
public class Person { public String Name; public int Age; //这是一个方法,用来输出对象的姓名和年龄 public void show(){ System.out.println(Name + Age); } }这样,一个类就定义好了,我们就可以基于这个类来创建一个对象:
Person man = new Person();
- 通过new关键字创建了一个叫做man的对象,这一过程就叫做类的实例化。
- 在这其中,man是一个引用类型
2.4 类和对象的说明
- 类只是一个模板,用来描述一个实体(对象),限定了类中有哪些成员。
- 类是一种自定义的类型。可以用来创建一个变量。
- 一个类可以实例化出多个对象。实例化的对象占用实际的物理空间,储存类成员变量。
- 可以把类的定义看作一个设计,不会占用物理空间,只有根据这个设计实例化出一个对象时,才会开辟空间来储存成员变量。
【附加】对象在内存中的存储
对象在内存中的存储可以简易理解为:
2.5 类中变量以及方法的访问
如果我们想访问类中的成员变量以及方法时,可以通过 对象名+‘.’来访问,具体过程如下所示:
运行结果:
三、this引用
我们先来看如下代码:
class Dog{ public String name; public int age; public void eat(){ System.out.println(name + "正在吃狗粮~~~"); } } //测试类 public class Text { public static void main(String[] args) { //创建两个对象 Dog dog1 = new Dog(); Dog dog2 = new Dog(); //进行成员变量的赋值 dog1.name = "小黑"; dog1.age = 5; dog2.name = "汪汪"; dog2.age = 3; //调用成员方法 dog1.eat(); dog2.eat(); } }- 在这其中,我们通过对象对成员变量赋值,并且调用成员方法。但是我们仔细一想,根据之前所学,对象在内存中的存储中,只储存了自己的成员变量等信息,并没有存储方法的相关信息。
- 所以我们调用的应是同一个方法。
- 既然是一个方法,那么这个方法又是如何区别dog1和dog2这两个狗的名字的呢?
答案是:在每一个非静态的方法中,都有一个隐藏的参数:this。this用来指代当前的对象。
(静态与非静态在之后会详细介绍)
public void eat(Dog this){ System.out.println(this.name + "正在吃狗粮~~~"); } //这两个方法的定义是等价的 public void eat(){ System.out.println(name + "正在吃狗粮~~~"); }在正常情况下,this这个参数是隐藏起来的,用来指代当前类,那么这个当前类又是什么意思呢?我们来看一下main方法里调用eat方法的语句:
dog1.eat();//dog1即是this指代的当前类(实际上是传参) dog2.eat();//dog1即是this指代的当前类(实际上是传参)
当我们用一个对象来调用非静态的成员方法时,当前对象就会作为一个参数,传参到非静态方法中的this参数上。所以虽然调用的是同一个方法,但是在参数上是有区别的,是不同的两个对象,自然也就能区分不同对象的名字。
【附加】一些建议
- 我们在调用成员变量/方法时,可以省略this,但是不建议
- 一方面是为了让代码看起来更加的严谨,是一个好的编程习惯
- 另一方面可以解决在构造方法中,参数名字和成员变量名字相同而出现赋值失败的问题
四、对象的构造以及初始化
我们在创建一个对象的时候,可以对其中的成员变量进行赋值,如下:
Dog dog1 = new Dog(); Dog dog2 = new Dog(); //进行成员变量的赋值 dog1.name = "小黑"; dog1.age = 5; dog2.name = "汪汪"; dog2.age = 3;
但是这样是否太过于冗杂呢?我们可不可以在创建类的同时进行成员变量的赋值呢? 这里就涉及到新的知识:构造方法。
4.1 构造方法
构造方法是一类特殊的方法,没有返回类型(包括void也不行),方法名和类名相同,参数可有可无。它会在创建对象的时候自动被调用。如果类中没有对构造方法的定义,JAVA会自动提供一个不带参数的构造方法。
class Dog{ public String name; public int age; //构造方法 public Dog(String name,int age){ this.name = name; this.age = age; } public void eat(){ System.out.println(this.name + "正在吃狗粮~~~"); } } public class Text { public static void main(String[] args) { //创建两个对象 Dog dog1 = new Dog("小黑",5);//在这里传参 Dog dog2 = new Dog("汪汪",3); //进行成员变量的赋值 // dog1.name = "小黑"; // dog1.age = 5; // dog2.name = "汪汪"; // dog2.age = 3; dog1.eat(); dog2.eat(); } }介绍完构造方法,咱们回到之前的问题:
- 为什么建议在非静态方法中调用成员变量建议保留this呢?
如果不保留this,将构造方法写成如下形式:
public Dog(String name,int age){ name = name; age = age; }运行结果:
我们发现成员变量并没有被赋值,原因如下:
- 局部的变量优先使用,如果没有this的引用,且当参数名和成员变量名相同时,会发生成员变量自己给自己赋值的情况,确实赋值了,只不过赋值的对象并不是成员变量,而是参数本身。
4.1.1 this的三种使用方式
- 调用成员变量
- 调用非静态成员方法
- 调用构造方法
前两种之前已经介绍过,接下来将详细介绍第三种用法:调用构造方法。
我们知道,在类中如果没有构造方法的定义,JAVA会自动提供一个不带参数的构造方法:
public Dog(){ }在这个方法中,同样有this引用,this调用构造方法的方式如下:
public Dog(){ this("小黑",9);//必须在第一行 } public Dog(String name,int age){ //实际上调用了这个构造方法 this.name = name; this.age = age; }我们在一个构造方法中可以用this调用另一个构造方法,但是这个this引用必须放在第一行。
五、封装
我们在使用手机的时候,其实并不知道手机内部是如何工作的,但是我们知道充电口可以充电、摄像头可以照相。这种把内部的一些实现方法隐藏起来,使用者不能直接访问,而只提供访问它们的渠道,这种情况就叫做封装。
5.1 private、default、public
- private 修饰的成员变量/方法只能在当前的的类中访问
- default 这种情况是默认权限,不加任何修饰符的情况,成员变量/方法可以在同一个包中被访问
- public 修饰的成员变量/方法/类可以任意被访问
5.2 具体实现方法举例
class Dog{ private String name;//在这个类的外部不能直接被访问 private int age;//在这个类的外部不能直接被访问 public Dog(String name,int age){ //构造方法 this.name = name; this.age = 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 void eat(){ System.out.println(this.name + "正在吃狗粮~~~"); } }在这段代码中,name和age不能直接被外部访问,但是可以通过调用其他方法来接收返回值得到相应的信息。
六、关于static
被这个修饰符修饰的方法、成员变量,被称为静态方法/变量。它们不依赖于对象的实例化,随着类的加载而被加载。
【附加】关于加载
JAVA语言不依赖于系统,而是有着独立的虚拟机:JVM 。源代码会被加载至JVM中,再由JVM将这些处理过的代码翻译成一条条的机器指令,使不同的系统可以识别并运行。
需要额外注意的是JAVA是具有选择性加载的特性,只有当使用到该类时,这个类才会被加载。
6.1 static修饰方法、成员变量
被static修饰的成员方法,成员变量不需要实例化一个对象来调用,直接使用类名+'.'就可以访问。
class Dog{ public static String name = "汪汪"; public int age = 6; public static void func(){ System.out.println("测试静态方法"); } } public class Text { public static void main(String[] args) { Dog.func();//直接用类名就可以访问,不依赖于对象 System.out.println(Dog.name); } }6.2 static修饰需要注意的事项
- static修饰的方法中,不能调用非静态方法。如果非要调用,需要实例化对象,用对象来调用。
- static修饰的方法不依赖于对象,所以没有this引用。
- 非静态方法可以直接调用静态方法,不需要实例化对象。
- stati修饰的成员变量不依赖于对象,一般用类名访问,但是也可以通过对象访问,这里不建议这样做。
七、代码块
代码块是被包含在花括号{}里的代码片段,在JAVA中,多数用来初始化数据。
7.1 静态代码块
static { name = "小黑"; //静态代码块 }7.2 实例代码块
{ age = 8; //实例代码块 }7.3 代码举例
class Dog{ public static String name = "汪汪";//就地初始化 public int age = 6; //就地初始化 static { name = "小黑"; //静态代码块 } { age = 8; //实例代码块 } } public class Text { public static void main(String[] args) { Dog dog = new Dog(); System.out.println(dog.age); System.out.println(Dog.name);//用类名访问 System.out.println(dog.name);//这样写也可以,但是不建议 } }在这里还会注意到一点:原本就地初始化的数据被覆盖了,这就涉及到执行顺序的问题。
执行的顺序:
(父类和子类的知识在之后的继承与多态会讲到)
八、对象的打印
我们来看下面的代码:
class Dog{ public String name ; public int age ; public Dog(String name, int age) { this.name = name; this.age = age; } } public class Text { public static void main(String[] args) { Dog dog = new Dog("小黑",12); System.out.println(dog);//直接打印,结果是什么呢? } }由于dog是一种引用类型,dog里实际上存储的是一个地址,所以输出结果是地址。
Dog 是类名,@是分隔符,在这之后的一串是转换后的哈希值,可以看作是地址。
如果我们查看源码:实际上调用的是toString
如果我们想要输出类中的成员变量,只需要重写这个方法就可以了。
class Dog{ public String name ; public int age ; public Dog(String name, int age) { this.name = name; this.age = age; } public String toString(){ //重写toString方法 return this.name + " " + this.age; } } public class Text { public static void main(String[] args) { Dog dog = new Dog("小黑",12); System.out.println(dog); } }关于重写,会在之后的继承与多态中讲到,目前只需要明确:
- 直接打印对象名,会输出地址
- 如果想要输出对象的信息,只需要在当前类中重新写一个toString方法
- 重写的要求:除了方法中的内容不同,其他都要求一致(返回值、方法名、参数名、参数顺序)。
- 局部的变量优先使用,如果没有this的引用,且当参数名和成员变量名相同时,会发生成员变量自己给自己赋值的情况,确实赋值了,只不过赋值的对象并不是成员变量,而是参数本身。
- 为什么建议在非静态方法中调用成员变量建议保留this呢?















