ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Java:12-类和对象的概念

Java:12-类和对象的概念

类和对象的概念

面向对象编程的概念-----------------------------
万物皆对象
面向对象指以属性和行为的观点去分析现实生活中的事物
面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言进行表达的过程
C语言:面向过程的语言
C++:面向过程又面向对象的语言
Java:面向对象的语言
面向过程:规定什么时候干什么,如老师布置的任务,关注这个过程
面向对象:看是否符号该对象,如是否符号老师的特征和行为,关注老师本身
举个例子:打开洗衣机,放衣服,放洗衣粉,清洗,烘干,这系列过程做成的结果就算面向过程
而面向对象则会先定义,人:打开洗衣机,放衣服,放洗衣粉,洗衣机:清洗,烘干
所以面向对象就算在面向过程的基础上规定了对应的操作由谁干
面向对象编程是软件产业化发展的需求
理解面向对象的思想精髓(封装,继承,多态),至少掌握一种编程语言
类和对象的概念------------------------------
对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空间中的一块存储区域
类简单来就是"分类",是对具有相同特征和行为的多个对象共性的抽象描述
在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性的成员变量以及描述行为的成员方法
类是用于构建对象的模板,对象的数据结构由定义它的类来决定
类的定义------------------------------
class类名{类体;}//如以下类的定义classPerson{}
注意:通常情况下,当类名由多个单词组成时,要求每个单词首字母都要大写
成员变量的定义------------------------------
class类名{数据类型 成员变量名=初始值;}//如以下成员变量的定义classPerson{Stringname;}
注意:当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首字母大写,对与命名规范,可以看这个博客:https://blog.csdn.net/lzy251168/article/details/126332645
对象的创建------------------------------
new类名();//没有名字的对象(栈区没有东西存)叫做匿名对象
注意:当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个过程叫做类的实例化
创建对象的本质就是在内存空间的堆区申请一块存储区域,用于存放该对象独有特征信息
引用的定义------------------------------
使用引用数据类型定义的变量叫做引用型变量,简称为"引用"
引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问
语法格式
类名 引用变量名;引用变量名.成员变量名//如下Personp=newPerson();//new Person()在堆的类型是Person类型,即引用也必须要与这个类型相关,否则不匹配//类似于数组的定义,如int[] i = new int[4];//new int[4]在堆的类型是int类型,那么i的类型也要与int类型相关,否则不匹配p.name="张飞";System.out.println(p.name);
案例题目------------------------------
编程实现Person类的定义和使用

注意:对于char来说,虽然看起来它默认是0,但是实际上他只有再计算的时候才代表0的(所以直接打印时,出现的是字符,而不是数字),也就是说,他保存的是一个空字符,再Ascii里面可以看到0对应的值(在第6章博客中可以看到)
保存过的文件放在硬盘,没保存的放在内存,CPU只可读取内存
cmd执行编译后的代码时JVM会将其加载到内存里,让CPU解析和执行

由上图,可知在方法区里存放了这个所有代码(实际上是字节码文件)
在运行时main方法是程序入口,先找main方法,main方法在栈区中,即栈给main方法申请内存空间(地盘)
而main方法又给他里面的一些变量分配内存空间(地盘),如0x10,即p这个引用变量的内存空间里存放的是0x10
而堆区的new Person()创建后到堆区,由于没有设置初始值,即他里面的值都是默认值
那么就可以根据p这个引用来获取对应地址在堆空间的数据
即可以说p就是0x10,就是ox10来获取堆的数据(类似于int a =2这个,可以说a就是2一样)
那么就可以说,将变量变为他内存空间的值后再使用,所以就有p.name这样的操作(即ox10.name)
这里说明一下方法区(了解即可):具体的方法区,实际上是最终指向,我们在堆中,基本只是操作变量,方法还是方法区的,具体可以看这个博客:https://www.cnblogs.com/promonkeys/p/10178976.html
局部变量都在栈区
/* 编程实现Person类的定义 */publicclassPerson{// 数据类型 成员变量名 = 初始值;,其中"=初始值" 通常可省略不写Stringname;//用于描述姓名的成员变量intage;//用于描述年龄的成员变量//可以不初始化//自定义成员方法实现所有成员变量的打印,方法不可以在方法里定义(注意:方法只有一份,多个实例使用的都是同一个方法,方法信息在方法区,成员变量在堆,由于方法区是线程共享,线程共享:所有线程都是同一个,所以多个实例使用的都是同一个方法)//在虚拟机中,调用方法时,会根据方法信息与变量进行一系列操作,从而最终操作结果,如返回值等等//简单来说,由于最终是字节码,所以解析后,自然可以进行处理(就如最开始的机器指令一样,所以不只是方法,如继承,构造方法等等操作)//返回值类型 方法名称(形参列表){ 方法体; }voidshow(){//成员变量和成员方法都属于类内部成员,因此可以直接访问成员变量不需要再加引用.的前缀System.out.println("我是"+name+",今年"+age+"岁了!");}//自定义成员方法实现将姓名修改为参数指定数值的行为voidsetName(Strings){name=s;}//自定义成员方法实现将年龄修改为参数指定数值的行为voidsetAge(inti){age=i;}//上面的两个可以降低耦合性,方便修改//自定义成员方法实现将姓名和年龄修改为参数指定数值的行为 下面的方法不推荐使用voidsetNameAge(Strings,inti){//修改其中一个,另外一个也会进行修改name=s;age=i;}//自定义成员方法实现可变长参数的使用 看作一维数组使用即可voidshowArgument(intnum,String...args){//可变长参数若在有其他参数时,一定要放在最后(否则报错,因为我无法判断该参数是可变长参数还是你的)System.out.println("num = "+num);for(inti=0;i<args.length;i++){System.out.println("第"+(i+1)+"个参数为:"+args[i]);}}//自定义成员方法实现姓名数值的获取并返回的行为StringgetName(){returnname;//返回数据并结束当前方法//...执行不到的}//自定义成员方法实现年龄数值的获取并返回的行为intgetAge(){//方法名可以改变的,但最好这样写returnage;}publicstaticvoidmain(String[]args){inta;a=0;//必须初始化(除非不使用)//也可以说是栈里面的要有值,即必须初始化//声明_01Person类型的引用指向_01Person类型的对象(注释有错不要紧,没有完美的)//数据类型(类名) 引用变量名 = new 类名();Personp=newPerson();//打印对象中的成员变量值//引用变量名.成员变量名//System.out.println("我是" + p.name + ",今年" + p.age + "岁了!"); //null 0p.show();System.out.println("--------------------------------------------------------------------");//修改成员变量的数值p.name="关羽";p.age=999;//再次打印修改后的数值//System.out.println("我是" + p.name + ",今年" + p.age + "岁了!"); //关羽 999p.show();System.out.println("--------------------------------------------------------------------");//通过成员方法的调用实现成员变量的修改p.setName("淳爸");//name = 淳爸; //实参给形参赋值p.setAge(1000);//age = 1000;p.show();System.out.println("--------------------------------------------------------------------");//通过成员方法同时修改姓名和年龄//p.setNameAge("大大",30);intia=30;p.setNameAge("大"+"大",ia);p.show();System.out.println("--------------------------------------------------------------------");//通过成员方法实现可变长参数的打印//当不确定形式参数个数时,可以用可变长参数,那么传入多少个实际参数,就有多少个形式参数p.showArgument(1);System.out.println("--------------------------------------------------------------------");p.showArgument(1,"参数1");System.out.println("--------------------------------------------------------------------");p.showArgument(2,"参数1","参数2");System.out.println("--------------------------------------------------------------------");//通过成员方法的调用实现成员变量数值的获取和打印Stringstr1=p.getName();System.out.println("获取到的姓名是:"+str1);intib=p.getAge();System.out.println("获取到的年龄是:"+ib);}}
案例题目------------------------------
编程实现Point类的定义,特征有:横坐标(整数),要求在main方法中声明Point类型的引用指向Point对象并打印特征
然后将横坐标修改为3和5后再次打印
/* 编程实现Point类的定义 */publicclassPoint{intx;//用于横坐标的成员变量inty;//用于纵坐标的成员变量//自定义成员方法实现成员变量数值的打印voidshow(){System.out.println("横坐标是:"+x+",纵坐标是:"+y);}//自定义成员方法实现将横坐标修改为参数指定数值的行为voidsetX(inti){x=i;}//自定义成员方法实现将纵坐标修改为参数指定数值的行为voidsetY(intj){y=j;}//自定义成员方法实现int类型的可变长参数的使用 看作一维数组使用即可voidshowArgument(int...args){//可变长参数若在有其他参数时,一定要在最后for(inti=0;i<args.length;i++){System.out.println("下标为"+i+"的元素是:"+args[i]);}}//自定义成员方法实现横坐标数值的获取并返回的行为intgetX(){returnx;}//自定义成员方法实现纵坐标数值的获取并返回的行为intgetY(){returny;}publicstaticvoidmain(String[]args){//声明Point类型的引用指向Point类型的对象Pointp=newPoint();//打印成员变量的数值//System.out.println("横坐标是:" + p.x + ",纵坐标是:" +p.y);//引用变量名.成员变量名(实参列表);//调用方法的本质就是根据方法名跳转过去执行方法体后再跳转回这个位置p.show();System.out.println("--------------------------------------------------------------------");//将横纵坐标修改为3和5后再次打印p.x=3;p.y=5;//System.out.println("横坐标是:" + p.x + ",纵坐标是:" +p.y);p.show();System.out.println("--------------------------------------------------------------------");//通过成员方法实现横纵坐标的修改p.setX(10);p.setY(20);p.show();// 10 20System.out.println("--------------------------------------------------------------------");//通过成员方法实现可变长参数的使用p.showArgument(1,2,3,4,5);System.out.println("--------------------------------------------------------------------");//通过成员方法的调用实现横纵坐标数值的获取和打印intia=p.getX();System.out.println("获取到的横坐标是:"+ia);intib=p.getY();System.out.println("获取到的纵坐标是:"+ib);}}
成员方法的定义------------------------------
class类名{//属于类的才会有成员二字返回值类型 成员方法名(形参列表){成员方法体;}}//如下代码classPerson{voidshow(){System.out.println("没事秀一下");}}
当成员方法名由多个单词组成时,要求从第二个单词起每个单词的首字母大写,成员变量也是这样
返回值类型------------------------------
返回值主要指从方法体内返回到方法体外的数据内容
返回值类型主要指返回值的数据类型,可以是基本数据类型,也可以是引用数据类型
当返回的数据内容是66时,则返回值类型写int即可,即返回值类型取决于返回的数据
在方法体中使用return关键字可以返回具体的数据内容并结束当前方法,return后面的代码不执行
当返回的数据内容是66时,则方法体中写return 66;即可
当该方法不需要返回任何数据内容时,则返回值类型写void即可
形参列表------------------------------
形式参数主要用于将方法体外的数据内容带入到方法体内部
形式参数列表主要指多个形式参数组成的列表,语法格式如下
数据类型 形参变量名1,数据类型 形参变量名2,...
当带入的数据内容是"hello"时,则形参列表写String s即可
当带入的数据内容是66和"hello"时,则形参列表写int i,String s即可
若该方法不需要带入任何数据内容时,则形参列表位置啥也不写即可
方法体详解------------------------------
成员方法体主要用于编写描述该方法功能的语句块
成员方法可以实现代码的重用(重复利用),简化代码
方法的调用------------------------------
引用变量名.成员方法名(实参列表);//如p.show(); //实参列表:实际参数的列表
实际参数列表主要用于对形式参数列表进行初始化操作,因此参数的个数,类型以及顺序都要完全一致
实际参数可以传递直接量,变量,表达式,方法的调用等
可变长参数------------------------------
返回值类型 方法名(参数的类型...参数名)//三个点表示省略,就是后面还有很多参数
方法参数部分指定类型的参数个数是可以改变的,也就是0~n个,就是当我们在里面可以加任意个参数
一个方法的形参列表中最多只能声明一个可变长形参,并且需要放到参数列表的末尾
成员变量在类里,方法体外,局部变量属于方法体内部的,所以局部变量通常都需要使用,即必须初始化(因为没默认值)
而成员变量可以不初始化(因为有默认值),因为用他的时候都会自动将他初始化
局部变量作用域从方法声明开始一直到方法结束
成员变量作用域从类声明开始一直到类结束
如果有两个方法如
voidfa(inti,intj,intn){System.out.println("1");}voidfa(int...i){System.out.println("1");}//在调用这个方法时,若有具体参数的方法,则调用有具体参数的方法,若没有,则调用有可变长参数的方法
方法的传参过程------------------------------
intmax(inta,intb){.........}inta=5;intb=6;intres=m.max(a,b);//m是引用变量 //他的类型里有max方法
为main方法中的变量a,b,res分配空间并初始化
调用max方法,为max方法的形参变量ia,ib分配空间
将实参变量的数值赋值到形参变量的内存空间中
max方法运行完毕后返回,形参变量空间释放
main方法中的res变量得到max方法的返回值
main方法结束后释放相关变量的内存空间

参数传递的注意事项------------------------------
基本数据类型的变量作为方法的参数传递时,形参变量数值的改变通常不会影响到实参变量的数值
因为两个变量有各自独立的内存空间
引用数据类型的变量作为方法的参数传递时,形参变量指向内容的改变会影响到实参变量指向内容的数值
因为两个变量指向同一块空间

若又将一个地址给arr1后,那么arr1就会指向另外一个堆区内存空间

当引用数据类型的变量作为方法的参数传递时,若形参变量改变指向后再改变指定的内容
则通常不会影响到实参变量指向内容的改变,因为两个变量指向不同的内存空间
内存结构之栈区------------------------------
栈用于存放程序运行过程当中所有的局部变量,一个运行的Java程序从开始到结束会有多次方法的调用
JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧
一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数,局部变量等数据
当某一个方法调用完成后,其对应的栈帧将被清除
传参的相关概念------------------------------
参数分为形参和实参,定义方法时的参数叫形参,调用方法时传递的参数叫实参
调用方法时采用值传递把实参传递给形参,方法内部其实是在使用形参
所谓值传递就是当参数是基本类型时,传递参数的值,比如传递i=10,真实传参时,把10赋值给了形参,当参数是对象时,传递的是对象的值,也就是把对象的地址赋值给形参
/* 编程实现参数传递的测试 自己写代码时容易犯的错误 */publicclassArgumentTest{//自定义成员方法打印参数传入的整数数据//ia = ib = 10;voidshow1(intia){ia=200;System.out.println("show方法中:ia = "+ia);//10 200}//自定义成员方法打印参数传入的数组内容voidshow2(int[]arr1){arr1=newint[2];//加上该行代码后,相当于在堆区中又重新申请一块内存空间arr1[0]=200;System.out.println("show方法中:arr1[0] = "+arr1[0]);//10 200}publicstaticvoidmain(String[]args){// //声明ArgumentTest类型的引用指向该类型的对象ArgumentTestat=newArgumentTest();//使用引用变量调用show1方法进行测试intib=10;at.show1(ib);System.out.println("main方法中:ib = "+ib);//10System.out.println("--------------------------------------------------------------------");//调用show2方法进行测试int[]arr2=newint[]{10,20};at.show2(arr2);System.out.println("main方法中:arr2[0] = "+arr2[0]);//10 200}}
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进