🔥Java解析----详解类和对象
🔥文章前提:
❓ Java是一门面向对象的语言,至于什么是对象,本篇博客将围绕这个主题展开,下面开始详解Java中类和对象的知识 👇
📙文章目录:👇
1.初步认识类和对象
❓ 类和对象之间存在着怎么样的关系呢👇
1️⃣ C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
2️⃣ JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
3️⃣ 面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。
面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来
❗️ 面向过程:
1.把冰箱打开 2. 把大象放入 3. 冰箱关起来
❗️ 面向对象: 打开冰箱,储存,关闭都是对冰箱的操作,是冰箱的行为。冰箱就是一个对象,所以只要操作冰箱所具备的功能,都要定义在冰箱中
【面向对象概念】
1️⃣. 面向对象是思考问题的一种思考方式,是一种思想。比如:概念与实例。理论与实践。名和实等等。
2️⃣. 类就是一类对象的统称。对象就是这一类具体化的一个实例。
3️⃣. 面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。
【面向对象设计】
1️⃣面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法!(被动的一方是数据的拥有者,主动的一方是执行者)
2️⃣开发时:找对象,建对象,用对象,并维护对象之间的关系。
⭐️简而言之 👇
面向对象就是用代码(类)来描述客观世界的事物的一种方式. 一个类主要包含一个事物的属性和行为
2.类和类的实例化
类就是一类对象的统称。对象就是这一类具体化的一个实例。
💨 简单的例子:👇
我们做月饼的模子就是一个类,而通过这个模子可以做出月饼,那么在这个例子当中,类就是那个模子,而月饼就是那个对象,所以月饼就是一个实体。一个模子可以实例化无数个对象。
💨 总的来说:👇
类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。
声明一个类就是创建一个新的数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。我们来看以下简单的声明一个类。👇
基本语法 👇
// 创建类
class <class_name>{
field;//成员属性
method;//成员方法
}
// 实例化对象
<class_name> <对象名> = new <class_name>();
❗️ class为定义类的关键字,ClassName为类的名字,{}中为类的主体。类中的元素称为:成员属性。类中的函数称为:成员方法
类的声明分为两步:👇
1️⃣ class定义类 👇
2️⃣ 由定义的类去实例化对象 👇
❓ 我们来看一下在内存上类的定义是怎样的 👇
类的实例化
用类类型创建对象的过程,称为类的实例化👇
- 类只是一个模型一样的东西,限定了类有哪些成员.
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东
西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
❓ 那么如何访问到对象中的属性呢
System.out.println(person.age);
System.out.println(person.name);
0
null
👉 我们看到成员成员变量的访问,是由指向类的引用类型+(.)便可以访问到对应的成员变量
❗️ 成员变量没初始化基本类型默认数值为:0,引用类型默认值:null
成员变量的初始化:👇
person.age = 11;
person.name = "bit";
❓ 那么如何访问到对象中的方法呢 👇
person.eat();
person.print();
bit正在吃饭
姓名bit年龄11
❓ 一个类实例化多个对象 👇
Person person = new Person();
Person person1 = new Person();
实例化多个对象时的内存情况 👇
❗️ 由于 person1 和 person2 是两块不同的内存,改变成员变量不会相互影响 👇
person.age = 11;
person.name = "bit";
person1.age = 19;
person1.name = "by";
System.out.println(person.age);
System.out.println(person.name);
System.out.println(person1.age);
System.out.println(person1.name);
11
bit
19
by
❗️ 注意事项
- new 关键字用于创建一个对象的实例.
- 使用 . 来访问对象中的属性和方法.
- 同一个类可以创建对个实例
3.类的成员
3.1.字段/属性/成员变量
👉 在类中, 但是方法外部定义的变量. 这样的变量我们称为 “字段” 或 “属性” 或 “成员变量”(三种称呼都可以, 一般不会严格区分).
注意事项👇
- 使用 . 访问对象的字段.
- “访问” 既包含读, 也包含写.
- 对于一个对象的字段如果没有显式设置初始值, 那么会被设置一个默认的初值.
默认值规则
1️⃣ 对于各种数字类型, 默认值为 0.
2️⃣ 对于 boolean 类型, 默认值为 false.
3️⃣ 对于引用类型(String, Array,以及自定制类), 默认值为 null
❗️ 注意事项:
1️⃣ null 在 Java 中为 “空引用”, 表示不引用任何对象. 类似于 C 语言中的空指针. 如果对 null 进行 . 操作就会引发异常
2️⃣ person2 可以引用指向 person 这个引用所指向的对象
3️⃣ 引用多次指向对象,引用仅指向最后一个对象
4️⃣ 引用不一定在栈上
3.2 方法 (method)
方法------> 用于描述一个对象的行为.
方法中还有一种特殊的方法称为:构造方法 (construction method)
在实例化对象的时候会被自动调用到的方法, 方法名字和类名相同, 用于对象的初始化.
虽然我们前面已经能将属性就地初始化, 但是有些时候可能需要进行一些更复杂的初始化逻辑, 那么就可以使用构造方法.
3.3 static 关键字
我们看这样一个代码
class Person{
public static int count;
}
public static void main(String[] args) {
Person person = new Person();
person.count = 1999;
System.out.println(person.count);
Person person1 = new Person();
System.out.println(person1.count);
}
1999
1999
❓ 我们看到两个结果都是 1999 ,按照上面所说两个对象的成员变量是两块不同的内存空间,不会互相影响,当 person1 没有初始化时默认数值应该为: 0 但是程序结果却是 1999,这两个count难道是同一个吗,这是为什么呢
👉 count 类型为静态成员变量
被 static 修饰成员变量也叫做类变量,是被放到方法区中的
方法区:👇
❗️ 所以可以得出结论:静态成员变量是属于类的
访问静态成员变量需要用类去访问(类名.静态成员变量/方法) 👇
Person.count = 10;
访问静态方法 👇
public static void staticfunc(){
System.out.println("静态方法");
}
public class TestDemo {
public static void main(String[] args) {
Person.staticfunc();
}
❗️ 由于静态成员变量的使用不需要实例化对象,所以静态成员变量是不依赖对象的,普通的成员变量需要引用去访问,所以普通成员变量是依赖对象的
❗️ 有关静态成员变量/方法中的注意事项 👇
一、 在普通方法中不可以定义静态的变量
1.static 定义的变量属于类,不可以在方法中出现
2.eat方法的调用,需要对应的对象引用来调用。但是如果可以定义static变量,Person类就可以调用
二、 在静态方法中不可以定义静态变量
1.static 定义的变量属于类,不可以在方法中出现
❗️ 以上两条总结:静态变量是不可以定义在方法中的
三、 普通方法可以调用静态方法
public void print(){
staticfunc();
System.out.println("姓名"+name+"年龄"+age);
}
静态方法类就可以调用所以可以在普通方法中调用
四、 静态方法中不可以调用普通方法
public static void staticfunc(){
print();//erro
System.out.println("静态方法");
}
静态方法不需要对象的调用,所以在静态方法中定义的普通方法没法调用
❗️ 一个对象存储到哪里与是否被 final 修饰无关
❓ 面试题:main 方法为什么是静态的???
👉main方法是不是静态的都可以,看 JVM 底层加载如何去实现
总结:👇
🔥 在代码中尽量少使用 static,这样的代码称为祖传代码,容易存在一些不合理的代码,代码不好修改
4.封装
❓ 如果在定义的类中随意更改了一个成员变量的名字,会导致在使用时出现未定义这样的问题,那应该怎么去解决呢 👇
在类的调用者看来,让他看不来成员变量的名字就可以了 👇
封装------->private
private int age;
可以看到把 age 改成 privat 类后程序报错了 👇
❗️ 这里修改的不是成员变量的名字,而是变量的属性,这里的 age 已经被封装起来,即当前属性只可以在当前类中使用
❓ 那应该如何使用 age 呢 👇
需要公开的时 set 和 get 接口在类中完成初始化和打印
4.2 getter和setter方法
快捷键 Alt + ins
选择Getter and Setter得到以下代码 👇
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
☝️ 在这其中赋值,返回数值都是可以的
❗️ 这样做的目的是使成员变量 / 方法更加安全,类的使用人员只需要关心接口
即可👌
如图样式使用即可:👇
public static void main(String[] args) {
Person person = new Person();
person.setAge(10);
System.out.println(person.getAge());
}
👉 总结:
1️⃣ private 不光能修饰字段, 也能修饰方法
2️⃣ 通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public, 就需要视具体情形而定. 一般我们希望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public.
5. 构造方法
5.1 基本语法
构造类型:👇
方法名和类名是相同的,且构造方法比较特殊,没有返回值
❓ 那构造方法是用来干什么的,这就需要我们了解一个对象的产生【对象的实例化】
实例化对象课以分为如下几部:👇
- 为对象分配内存
- 调用合适的构造方法
☝️ 这两步完成后对象才真正产生了
❗️ 注意:👇
构造方法不止一个
不带参数的构造方法:👇
class Person{
public Person(){
System.out.println("Person():不带参数的构造方法");
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
}
}
当由类实例化对象时就会调用构造方法:👇
Person():不带参数的构造方法
❗️ 当没有指定的构造方法时,编译器默认生成一个不带参数的构造方法,也就是说一个类至少有一个构造方法
❗️ 这里如果封装 Person 在其他类中不可以被调用,只可以在该类里进行操作
private Person(){
System.out.println("Person():不带参数的构造方法");
}
☝️ 会引发错误
调用带有参数的构造方法:👇
public Person(String name){
this.name = name;
System.out.println(this.name);
}
public class TestDemo {
public static void main(String[] args) {
Person person1 = new Person("bit");
}
}
bit
❗️ 如果当前类有其他的构造方法,那么编译器不会帮我们生成不带有参数的构造方法
❗️ 构造方法之间可以构成重载
5.2 this关键字
this 表示当前对象引用(注意不是当前对象). 可以借助 this 来访问对象的字段和方法
👉 因为 this 只是走完了对象实例化的第一步分配内存空间,第二步还没进行,所以这里是表示对象的引用
❓ 面试问题:
this 和 super 的区别:
super后期讨论
❓ 先看 this 有什么作用 👇
- this.data 调用当前对象的属性
- this.func() 调用当前对象的方法
- this() 调用当前对象的构造方法
1️⃣ 调用当前对象的属性 👇
public Person(String name){
this.name = name;
System.out.println(this.name);
}
2️⃣ 调用当前对象的方法👇
public void eat(){
System.out.println("吃饭");
}
public void print(){
this.eat();
}
3️⃣ 调用当前对象的构造方法
public Person(){
this("bit");//调用带有一个参数的构造方法
System.out.println("Person():不带参数的构造方法");
}
public Person(String name){
this.name = name;
System.out.println(this.name);
}
❗️ 先调用带有参数的构造方法,再调用不带参数的构造方法
❗️ this() 必须放在第一行,也就是说只能写一个 this()
❗️ this() 只能存放在构造方法中
6. 认识代码块
6.1 什么是代码块
使用 {} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种 👇
- 普通代码块
- 构造块
- 静态块
- 同步代码块
6.2实例代码块
{//定义在类中
System.out.println("实例代码块");
}
6.3静态代码块
static {
System.out.println("静态代码块");
}
6.4代码块的使用
❓ 知道了如何定义代码块,那它怎样被调用呢
Person person = new Person();
静态代码块
实例代码块
👉 在实例化对象时候就被调用了,并且静态代码块先运行,然后是实例代码块,最后是构造方法
❗️ 实例化多个对象时,静态代码块只被执行一次
Person person = new Person();
Person person1 = new Person("bit");
静态代码块
实例代码块
实例代码块
❗️ 不用实例化对象时,静态代码块也可以被执行 👇
public static int count;
Person.count = 10;
静态代码块
可以利用代码块对成员变量赋值 👇
{
this.age = 99;
System.out.println("实例代码块");
}
static {
count = 99;
System.out.println("静态代码块");
}
❗️ 如果都是静态的,那么和定义的顺序是有关系的
❗️ 类的定义顺序:字段在前,其他在后
❗️ 上图代码当 cout 没有初始化默认数值为 99
7.补充说明
7.1 toString方法
❓ 当程序打印引用类型 person 时:👇
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
Person@1b6d3586
☝️ 这里得到的时被哈希加密过的地址
❓ 我们看下编译器底层是如何实现的 👇
按住Ctrl键鼠标左击:println 👇
同样的方法点击valueOf:👇
同样的方法点击toString:👇
👉 我们便知道了上图的地址是如何得出的了,是一个toString实现的
模拟实现一下这个toString 👇
class Person{
public String toString(){
return "by";
}
}
❓ 当重新自定义一个toString的时候,程序打印的结果是什么呢
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
by
❗️ 我们发现这次程序的运行没有运行编译器的object toString 而是运行了我们自己的toString方法,是因为发生了动态绑定,动态绑定后期介绍
❗️ 注意这里的toSring名字要完全一样,才会调用自己的
👉 我们也可以让编译器帮我们生成这样的 toSting ,这里可以用到快捷键
Alt + ins 👇
点击 toString 编译器自动生成 👇(按住Ctrl可以多选)
生成的代码:👇
@Override//重写
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
介绍两个概念:👇
- 系列化:对象 --> 字符串
- 反序列化: 字符串—> 对象
7.2匿名对象
匿名只是表示没有名字的对象
- 没有引用的对象称为匿名对象.
- 匿名对象只能在创建对象时使用.
- 如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象.
public class Main {
public static void main(String[] args) {
new Person("caocao",19).show();//通过匿名对象调用方法
}
}
8.练习
8.1.模拟实现计算器
全部代码:👇
class Calculator{
private int num1;
private int num2;
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public int add(){
return num1+num2;
}
public int del(){
return num1-num2;
}
public int cheng(){
return num1*num2;
}
public double chu(){
return (num1*1.0)/num2;
}
}
public class TestDemo2 {
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.setNum1(3);
calculator.setNum2(2);
System.out.println(calculator.add());
System.out.println(calculator.del());
System.out.println(calculator.cheng());
System.out.println(calculator.chu());
}
}
运行结果:👇
5
1
6
1.5
8.2.交换两个数值
class MyValue {
public int val;
}
public class TestDemo3 {
public static void swap(MyValue myV1, MyValue myV2) {
int tmp = myV1.val;
myV1.val = myV2.val;
myV2.val = tmp;
}
public static void main(String[] args) {
MyValue myValue1 = new MyValue();
myValue1.val = 10;
MyValue myValue2 = new MyValue();
myValue2.val = 20;
swap(myValue1, myValue2);
System.out.println(myValue1.val + " " + myValue2.val);
}
}
20 10
以上就是 Java 类和对象的知识,如果有所帮助还请一键三连,谢谢大家的支持!!!
💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞💞