java 面向对象三大特性之封装 万字详解(超详细)

简介: Java 面向对象三大特性之封装,详细讲解了private关键字,this关键字,以及构造器,一文讲透!

目录

前言 :

一、为什么需要封装 :

       前言 :

       1.封装的好处 :

       2.java中的常见封装体:

二、封装简介 :

       1.封装的概念 :

       2.封装的关键 :

三、private关键字(重要) :

       1.封装的必要利器—private介绍:

               Δ不用private的代码演示 :

       2.基本概念:

       3.特点 :

       4.用法 :

       5.private关键字代码演示 :

       6.setter,getter方法展示(重要) :

               ①介绍:

               ②如何定义setter,getter方法 :

               ③代码演示 及 问题延申 :

       7.关于public关键字 :

四、this关键字(重要) :

       1.基本概念 :

       2.特点 :

       3.用法 :

       4.作用 :

       5.代码演示 :

               ①private关键字演示中Phone类setter方法的强龙地头蛇布局定式冲突的解决 :

               ②this关键字调用成员变量(属性)的演示 :

               ③this关键字调用成员方法(行为)的演示 :

       6.深入理解this关键字 :

               图解  :

               代码演示 :

       7.hashCode相关(了解即可) :

               ①介绍 :

               ②hashCode的常规协定 :

五、构造器详解(重要) :

       1.什么是构造器 :

       2.那么,谁来创建对象呢?

       PS: Java创建对象的内存图解 :

       3.构造器的定义格式 :

       4.构造器需要满足的要求:

       5.注意事项(重要):

       6.代码演示 :

               ①我们先不定义构造器,测试一下是否能成功创建对象。    

               ②下一步,我们定义一个自己的无参构造,

               ③第三步,我们建立一个有参构造,

               ④在仅含一个带参构造的前提下,测试空参构造:

               ⑤同时定义了无参构造和有参构造:

       7.关于javap命令(了解即可) :

               ①介绍 :

               ②位置 :

               ③图示 :

               ④使用格式 :

               ⑤常用指令 :

               ⑥代码演示,javap命令演示 :

       8.构造器的改进(🐂🖊) :

六、标准代码JavaBean!(编程之美)

       1.Java语言编写类的标准规范 :

       2.标准JavaBean类代码演示 :

七、总结 :


前言 :

       Hey,guys.从这篇博文开始,我们就要正式进入java面向对象三大特性的学习了。这三大特性:封装、继承、多态构成了面向对象的灵魂,也是面向对象和面向过程最大的差别。所以,学好三个特性对于一个java人来说,非常重要!这篇博文的内容包括但不限于封装的介绍private关键字详解this关键字详解构造器详解JavaBean介绍等等。注意,代码中的注释往往包含了讲解,别错过。

一、为什么需要封装 :

       前言 :

       我们知道,类是属性和行为的集合,是一个抽象概念。而对象是该类事物的具体体现,是一种具体存在。而当我们需要对某个类中的一些数据进行保护,不想让外界随意修改它们时,或者当我们想调用某个类中的方法,但又不想将该方法的实现细节暴露出来,就需要用到java这个听起来牛逼哄哄的特性了,“封装"。

       1.封装的好处 :

               提高代码的安全性

               提高代码的复用性

               将复杂的事情变得简单化

       2.java中的常见封装体:

      类 :

               安全性 : 调用者无法直接修改类中的数据(属性)。

               复用性 : 同一个类可以被重复使用。

               简单化 : 类的对象包含了更多的功能,使用也更方便。        

       方法:

               安全性 : 调用者不知道方法的具体实现。

               复用性 : 定义的方法可以被多次调用。

               简单化 : 将繁多的代码以一个方法的形式呈现,仅通过调用方法就可以实现功能,代码维护也变得简单。

二、封装简介 :

       1.封装的概念 :

               将一系列相关事物的共同的属性和行为提取出来,放到一个类中,同时隐藏对象的属性和实现细节,仅对外提供公共的访问方式。

               Δ注意,JavaBean类就可以看作是封装的完美案例。JavaBean我们后面会说到。  

       2.封装的关键 :

               ①封装使数据被保护在内部。

               ②绝对不可以让类中的方法直接访问其他类的数据(属性),程序仅通过对象的方法与对象的数据进行间接交互。

               封装可以使得我们对传入的数据进行校验和限制,加强了业务逻辑。

三、private关键字(重要) :

       1.封装的必要利器—private介绍:

               我们之前写类的时候,从来没有用过private(假设你才刚学,确实没用过🤗)。那不用private使用类时的效果是什么呢,我们可以在本包下的其他类随意的使用该类的属性和行为。平时我们自己玩玩儿啥的雀氏也没啥,但是将来开发怎么可能让你这么专横哈哈。所以,我们要学会去保护它们。So,如何保护呢?private上就完了。

               现在我们先给大家看一下不用private是怎样的?假设(其实就是定义了)定义一个Phone类(手机类),在Phone中定义一些属性和方法,均不用private修饰,甚至方法我们也暂且不用static修饰(假设你还没学嘛,因为我还没讲捏🤗),然后再新建一个TestPhone类,测试其中的属性和方法。

               Δ不用private的代码演示 :

               Phone类代码如下

packageknowledge.define;
publicclassPhone {
//    成员变量:Stringbrand;    //手机牌子Stringmodel;    //手机型号Stringname;     //手机持有者//    成员方法:publicvoidcall(Stringname) {
System.out.println("给我"+name+"打个电话");
    }
publicvoidsendMessage() {
System.out.println("🐔 : 律师函告CSDN🔨");
    }
publicvoidlistenMusic() {
System.out.println("🐔你太美~,🐔你实在是太美~");
    }
}

image.gif

               TestPhone类代码如下 :

packageknowledge.define;
/*** 手机类的测试*/publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.调用成员变量,并打印//给成员变量赋值p.brand="Huawei";
p.model="p40";
p.name="Kyrie";
//打印成员变量的值System.out.println(p.brand);
System.out.println(p.model);
System.out.println(p.name);
System.out.println("________________________");
//3.调用成员方法p.call("KunKun");
p.sendMessage();
p.listenMusic();
    }
}

image.gif

              输出结果如下图 :

image.png

               注意看TestPhone类中的代码,我们是可以通过创建对象,以“对象.” 的形式直接访问Phone类中的属性,可能你一听也觉得没什么,但其实这是一件顶可怕的事儿😱。

       2.基本概念:

              private [ˈpraɪvət] ,私有的。private是Java四种访问权限修饰符中的一种,关于访问权限修饰符,大家先了解即可,之后讲到继承时,我们会详细地介绍四种访问权限修饰符。

       3.特点 :

              Δ被修饰的成员只能在本类中访问。其他类无法直接访问本类中被private修饰的成员。

       4.用法 :

               修饰成员变量 :

               private 数据类型 变量名;

              修饰成员方法 :

               private 返回值类型 方法名 (形参列表) { //方法体 }

       5.private关键字代码演示 :

               以我们刚刚演示的Phone类和TestPhone类为栗,我们给Phone类中的成员变量加上private修饰符,TestPhone类保持不变。Phone类代码如下 :

packageknowledge.define;
publicclassPhone {
//    成员变量:privateStringbrand;    //手机品牌privateStringmodel;    //手机型号privateStringname;     //手机持有者//    成员方法:publicvoidcall(Stringname) {
System.out.println("给我"+name+"打个电话");
    }
publicvoidsendMessage() {
System.out.println("🐔 : 律师函告CSDN🔨");
    }
publicvoidlistenMusic() {
System.out.println("🐔你太美~,🐔你实在是太美~");
    }
}

image.gif

               这时候你会发现,这**刚加上private关键字就报错了,如下图所示 :

image.png          

 IDEA提示我们有两条相关问题。什么是相关问题呢?意思就是问题本身不是在当前类,但是出了问题的类呢,又与当前类有关系。显然,只能是TestPhone类出了问题!如下图:            image.png              

明明白白,它提示我们:这些个变量都有private修饰🌶!你不能直接使用!  

               这下很多小伙伴儿要蒙圈了!不加private嫌我不保护数据,加上又不让我用,这**不是耍👴吗?让👴怎么玩儿?

               这位👴您先别生气!马上我们就要隆重介绍新的嘉宾出场 : setter,getter方法!

       6.setter,getter方法展示(重要) :

               ①介绍:

              setter[ˈsetər] ,制定者,安排者。

              getter[ˈɡetər] ,获得者。

               setter和getter其实指的分别是setXxx和getXxx两个函数,当然了,相信聪明的你看名字也能猜出来!setXxx可以修改对应属性的值,而getXxx则可以获取对应属性的值比方说,假设有一个私有的brand(品牌)属性,我们可以通过函数setBrand来修改brand属性的值,而通过getBrand来获取对应属性的值。                

               ②如何定义setter,getter方法 :

               两种方法 : 手写。或者快捷键。

               当然,对于初学者来说,当然是建议大家先手写,写熟练了你再用快捷键嘛,快捷键的方法up已经专门写过一篇博客,在此不再赘述,有兴趣可以看看。现在我们来讲一讲,如何去手写定义这两个函数

               首先,setXxx() 方法,肯定需要你去传入一个值,不然谁知道你要改成啥呀。然后这个函数还必须将接收到的值赋值给类中的对应属性(对应属性即指setXxx中的Xxx),否则对应属性肯定不会修改成功,你的目的就是修改对应属性的值嘛,假如你创建该属性时未进行显式初始化,那么该属性就是默认值。因此,setXxx() 方法的关键两步骤就是:传入值和赋值值,方法体中仅需要一句赋值语句,当然,函数的返回值类型就是void了,你只需要修改就好。

               其次,getXxx() 方法,我们想达到的效果是:每次调用该函数都可以返回对应属性的当前值,所以,getXxx() 方法是一定有返回值的,而返回值类型取决于你后面的Xxx属性本身的数据类型,对应返回就好。而且,getXxx() 方法的方法体中,仅需要"return Xxx; "一句代码就可以,简洁高效。

               ③代码演示 及 问题延申 :

               新的Phone类代码如下 :

packageknowledge.define;
publicclassPhone {
//成员变量:privateStringbrand;   //手机品牌privateStringmodel;   //手机型号privateStringname;    //手机持有人//setter,getter方法//brand的getter方法publicStringgetBrand() {
returnbrand;
    }
//brand的setter方法publicvoidsetBrand(Stringb) {
brand=b;
    }
//model的getter方法publicStringgetModel() {
returnmodel;
    }
//model的setter方法publicvoidsetModel(Stringm) {
model=m;
    }
//name的getter方法publicStringgetName() {
returnname;
    }
//name的setter方法publicvoidsetName(Stringn) {
name=n;
    }
//成员方法:publicvoidcall(Stringname) {
System.out.println("给我"+name+"打个电话");
    }
publicvoidsendMessage() {
System.out.println("🐔 : 律师函告CSDN🔨");
    }
publicvoidlistenMusic() {
System.out.println("🐔你太美~,🐔你实在是太美~");
    }
}

image.gif

               有了setter,getter方法,我们就可以在TestPhone类中测试它们了,新的TestPhone类代码如下 :

packageknowledge.define;
/*** 手机类的测试*/publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.调用成员变量,并打印//给成员变量赋值p.setBrand("Huawei");
p.setModel("Mate40");
p.setName("Cyan");
//打印成员变量的值System.out.println("啥手机啊?"+p.getBrand());
System.out.println("废话,我不知道华为?我问你什么型号:"+p.getModel());
System.out.println("谁的手机啊?"+p.getName());
System.out.println("________________________");
//3.调用成员方法p.call("KunKun");
p.sendMessage();
p.listenMusic();
    }
}

image.gif

                输出结果如下 :

image.png    

😁效果不错。              

               这时候,就要有p小将(personable小将,指风度翩翩的人!)要说理了:诶诶诶,up你难道没发现吗,你的setter方法体中形参的定义不符合见名知意的效果!我把其中的一个setter方法拿出来给大家看看 :

publicvoidsetName(Stringn) {
name=n;
}

image.gif

               我趣,还真是这样,不愧是p小将😭,6。没错,所谓见名知意,就是指看到变量名就可以基本确定这个变量是干嘛的,但是你看我们写得setter方法,传入的形参变量定义成了n,要知道n开头的英语单词可是多的很捏,谁知道你表示名字呢?因此这么定义形参名无法满足“见名知意”的效果,降低了代码的可读性和逻辑性

               好,改!下面我们把形参名统一改成成员变量名,如下 :

image.png              就让我们来看看p小将的方法能不能行得通。        

               再次运行TestPhone类结果如下 :

image.png

               我趣?!这时候很多小伙伴儿要懵了,这咋还一问三不知了。

              出现这个问题的原因也很好解释

               大家都知道一句话吧,叫“强龙不压地头蛇”。没错,仔细看我们定义的setter方法,可以明确地看出,setter方法的形参列表都定义了局部变量,都不为空! 而Java中变量的使用规则是“就近原则”。即局部位置-> 成员位置-> 父类-> 更高的父类-> ...... -> Object如果一直到Object还没找到这个变量,报错!(Object是所有类的顶层父类,先了解一下即可,之后的继承特性中我们会讲到)。那既然现在setter方法内(局部位置)定义了形参,方法内部当然是优先使用这个定义的形参喽!所以,如果仅仅这么更改的话,达到的效果想必你也猜到了,没错,就是形参变量自己赋值给了自己,而成员变量,也就是我们要更改的属性,却仍然是String类型的默认值null

               其实,大家只要把鼠标悬停在右边的变量上,智能的IDEA就会自动报出提示 : 该变量自己赋值给了自己。如下图 :

image.png

               因此,我们需要想办法让左面的变量name能够正确表示成员变量name,而让右边的变量name,依旧表示我们的局部变量name,即接收用户传入的参数。可是,我们怎样才能达到这样的愿景呢?                

               😋,问得好,这就需要用到我们真正牛逼哄哄的this关键字。                

       7.关于public关键字 :

               在讲this关键字之前,稍微穿插一下关于public关键字的那些事儿。

               public[ˈpʌblɪk] 公众的,公有的,公开的。很明显,这是和private反着来的访问权限修饰符。public,是Java四种访问权限修饰符之另一个。

               public可以用来修饰类,成员变量,成员方法等,被public修饰的内容可以在任意类中访问。因此,public是访问权限最高的修饰符。其实吧,现在说太多也没啥用,直接说一个结论吧,记住就行。

               private 一般用来修饰成员变量(属性)

               public 一般用来修饰成员方法(行为)

四、this关键字重要) :

       1.基本概念 :

               this [ðɪs],这、这个,表示对本类对象的引用

               Java虚拟机会给创建的每个对象分配this,代表当前对象

       2.特点 :

               每一个创建的对象都有一个this属性,指向该对象本身(类似于指针,但在Java中叫做引用),因此this可代表当前对象,把它当作当前对象来看待。

       3.用法 :

               ①this.属性名;                  (可调用当前对象的属性,this.属性名就是当前对象的属性)

               ②this.方法名(参数);      (可调用当前对象的方法)

               知识延申 :

                       PS : this(参数列表) 可以访问本类的构造器构造器下面会讲到)。但要注意

                       Δ此时this后不需要加"."。

                       Δ该途径只能在构造器中使用,且使用时必须置于构造器的首句。我们称之为“构造器的复用”。

       4.作用 :

               可以解决类似我们刚刚遇到了“强龙不压地头蛇”的冲突问题。即形参名与属性名的重名问题。

       5.代码演示 :

               ①private关键字演示中Phone类setter方法中的强龙地头蛇布局定式冲突的解决 :

               刚才p小将一针见血地指出了我们的setter方法中,形参名无法见名知意的问题,让我们难堪,这下我们可以回击p小将了。走起 :

              Phone代码如下 :

packageknowledge.define;
publicclassPhone {
//成员变量:privateStringbrand;   //手机品牌privateStringmodel;   //手机型号privateStringname;    //手机持有人//setter,getter方法 (在setter方法中使用了this关键字来解决强龙地头蛇的冲突问题)//brandpublicStringgetBrand() {
returnbrand;
    }
publicvoidsetBrand(Stringbrand) {
this.brand=brand;
    }
//modelpublicStringgetModel() {
returnmodel;
    }
publicvoidsetModel(Stringmodel) {
this.model=model;
    }
//namepublicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
//成员方法:publicvoidcall(Stringname) {
System.out.println("给我"+name+"打个电话");
    }
publicvoidsendMessage() {
System.out.println("🐔 : 律师函告CSDN🔨");
    }
publicvoidlistenMusic() {
System.out.println("🐔你太美~,🐔你实在是太美~");
    }
}

image.gif

               我们再来运行TestPhone类,看一下属性有没有被成功赋值。TestPhone类代码如下:

packageknowledge.define;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.调用成员变量,并打印//给成员变量赋值p.setBrand("Huawei");
p.setModel("Mate40");
p.setName("Cyan");
//打印成员变量的值System.out.println("啥手机啊?"+p.getBrand());
System.out.println("废话,我不知道华为?我问你什么型号:"+p.getModel());
System.out.println("谁的手机啊?"+p.getName());
System.out.println("________________________");
//3.调用成员方法p.call("KunKun");
p.sendMessage();
p.listenMusic();
    }
}

image.gif

              运行结果 :

image.png

               可以看到三个String类型的属性都再次被成功赋值了,this 牛逼👍。其实,如果你使用快捷键生成了getter和setter方法,你会发现IDEA自动写出来的setter方法就是这么一回事儿:

publicvoidsetXxx(数据类型形参名xxx) {
this.形参名xxx=形参名xxx;     //成员变量xxx == this.形参名xxx}

image.gif

               这样的setter方法其实就是正确的,常规的,一写中的的写法!😀                    

               ②this关键字调用成员变量(属性)的演示 :

                       我们仍然使用 Phone类 与 TestPhone类 做演示绝不是因为懒得建新的演示类的了(bushi),我们在Phone中定义一个age成员变量表示手机的累计使用年限,再定义一个printAge()方法,来打印age变量的值,特别的,我们在printAge() 方法内再定义一个局部变量age,并试图在该方法内同时打印出局部变量age和成员变量age。然后我们在TestPhone类中创建一个Phone类对象,并利用创建的Phone类对象来调用printAge() 方法。

                       Phone类代码如下 :

packageknowledge.define;
publicclassPhone {
//成员变量:privateintage;        //手机累计使用年限//this 关键字对于属性的应用:publicvoidpintAge () {
intage=10;
/*此处在nameShow()方法内也定义了一个age的整型变量,与成员变量age同名,形成了强龙地头蛇布局定式。*///直接输出的age毫无疑问是地头蛇age。System.out.println("根据就近原则,没有加this关键字的age变量肯定是局部变量10呀:"+age);
//若想利用此函数来输出强龙age,则需要用到this关键字System.out.println("加上this关键字后,就可以在局部位置输出成员变量:"+this.age);
    }
}

image.gif

               TestPhone类代码如下

packageknowledge.define;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.调用成员方法p.pintAge();
    }
}

image.gif

               输出结果 :

image.png

可以看到,第一个没有用this关键字的age变量,其输出结果的确是为它赋的值10。但是,我们要注意,因为这次并没有用setAge修改age属性的值,因此输出属性age值为0整型的默认值等于0)。        

               但是,这么看对比好像不强烈,我们用setter方法来更改一下age属性的值,并将打印age的函数增加一个形参age,在显式赋值语句之前先输出传入的形参。

              Phone类代码如下

packageknowledge.define;
publicclassPhone {
//成员变量:privateintage;        //手机累计使用年限//setter,getter方法publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
//this 关键字的使用:publicvoidpintAge (intage) {
/*注意,当我们在形参列表中定义了age变量时,方法体中就不能重复定义age变量了,只能对它进行赋值更改*/System.out.println("调用pringAge() 方法时,传入的实参是多少呀:"+age);
age=10;       
//直接输出的age毫无疑问是地头蛇age。System.out.println("根据就近原则,没有加this关键字的age变量肯定是局部变量10呀:"+age);
//若想利用此函数来输出强龙age,则需要用到this关键字System.out.println("加上this关键字后,就可以在局部位置输出成员变量:"+this.age);
    }
}

image.gif

               TestPhone类代码如下 :

packageknowledge.define;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.给成员变量赋值p.setAge(11);    //这个11是赋给了成员变量age//3.调用成员方法p.pintAge(5);    //这个5是赋给了printAge的形参age    }
}

image.gif

               输出结果:

image.png        

我们看到成员变量age的值不再是默认的0了,而是我们通过setAge() 更改后的11。

               ③this关键字调用成员方法(行为)的演示 :

               我们在Phone类中定义一个私有方法,如下 :

 

packageknowledge.define;
publicclassPhone {
//定义一个私有的方法(无实际意义,仅作为演示)privatevoidicon() {
System.out.println("我是练习时长两年半的个人练习生:KunKun");
    }
}

image.gif

               当我们想在TestPhone类中直接调用icon() 该方法的时候,IDEA会提示报错,如下图所示:

image.png

               这种情况下,如果我们想继续调用该方法,就需要用到this关键字了。

               我们在Phone类中定义一个新的公共的方法,然后在这个新方法中通过this关键字来调用icon方法,如下 :

 

packageknowledge.define;
publicclassPhone {
//定义一个私有的方法(无实际意义,仅作为演示)privatevoidicon() {
System.out.println("我是练习时常两年半的个人练习生:KunKun");
    }
//通过this关键字解决私有函数无法直接调用的问题publicvoiddemo() {
this.icon();
    }
}

image.gif

               然后我们在TestPhone类中调用demo() 方法,就可以成功间接调用 icon方法,TestPhone类代码如下

packageknowledge.define;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonep=newPhone();
//2.调用成员方法p.demo();
    }
}

image.gif

               输出结果 :

image.png

       6.深入理解this关键字 :

               this关键字的本质到底是什么呢?

               其实,JVM在堆空间给对象分配空间时,每个对象都有一个隐藏的属性this,this指向该对象本身。即,如果用C语言来解释的话,this就是一个指向堆空间中对象本身的指针,只不过在Java中没有指针,叫做引用而已。this自己是对象的一部分,它也在堆空间,但是它又指向了它自己。

               光这么说多少有丶带抽象,来张内存图直观的表示一下,如下图:

               图解  :

image.png

               一看图就明白了,就是这么回事儿。当然,我们还可以通过另一种直观的方法来理解this,我们可以分别输出创建的Phone类对象和this对象的哈希码值,并进行比较。进行该操作需要用到hasCode方法(之后我们会讲到hasCode)。

               代码演示 :

               Phone类代码如下

packageknowledge.define;
publicclassPhone {
//成员变量:privateStringbrand;   //手机品牌privateStringmodel;   //手机型号privateStringname;    //手机持有人//setter,getter方法publicStringgetBrand() {
returnbrand;
    }
publicvoidsetBrand(Stringbrand) {
this.brand=brand;
    }
publicStringgetModel() {
returnmodel;
    }
publicvoidsetModel(Stringmodel) {
this.model=model;
    }
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
//定义一个方法,用来输出当前this对象的哈希码值。publicvoidprintThisHasCode() {
System.out.println(this.hashCode());
    }
}

image.gif

               TestPhone类代码如下

packageknowledge.define;
/*** 手机类的测试*/publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.创建对象Phonephone1=newPhone();
Phonephone2=newPhone();
//2.调用成员变量,并打印//给成员变量赋值phone1.setBrand("Huawei");
phone1.setModel("Mate40");
phone1.setName("Cyan");
System.out.println("输出phone1对象的哈希码值 : "+phone1.hashCode());
System.out.print("输出this对象的哈希码值 : ");
phone1.printThisHasCode();
System.out.println("------------------------------------");
phone2.setBrand("Huawei");
phone2.setModel("p40");
phone2.setName("Five");
System.out.println("输出phone2对象的哈希码值 : "+phone2.hashCode());
System.out.print("输出this对象的哈希码值 : ");
phone2.printThisHasCode();
    }
}

image.gif

              输出结果

image.png      

               可以看到, this的哈希码值和当前对象保持一致,因此我们可以证明:谁调用本类属性或者行为,this就指向谁。

       7.hashCode相关(了解即可) :

               ①介绍 :

                       public int hashCode() :

                       该方法可以根据地址值进行计算,然后返回该对象的哈希码值。支持此方法是为了提高哈希表的性能(例如java.util.Hashtable提供的哈希表)。

               ②hashCode的常规协定 :

                       Δ在java应用程序执行期间,在对同一对象多次调用hashCode方法时,必须一致地返回相同的整数,前提是将对象进行equals比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数元需要保持一致。

                      Δ如果根据equals(Object)方法,如果两个对象是相等的,那么对这两个对象中的每个对象调用hasCode方法都必须生成相同的整数结果。

                       Δ如果根据equals(java.lang.Object)方法比较后,两个对象不相等,那么对两个对象中的任一对象上调用hasCode方法不要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

五、构造器详解(重要) :

       1.什么是构造器 :

               构造器,也叫构造方法,指用来帮助创建对象的方法,但仅是帮助。它不是用来创建新对象的,而是完成对新对象的初始化

      2.那么,谁来创建对象呢?

               new关键字Java通过new关键字来创建对象,并在内存中开辟空间,然后使用构造器完成对象的初始化工作

      PS: Java创建对象的内存图解 :

               up之前写过的一篇博文详细介绍了Java创建新对象,在内存中实际发生了什么,有助于初学者快速理解new关键字,有兴趣的小伙伴儿可以点击链接查看,链接如下https://blog.csdn.net/TYRA9/article/details/128508466?spm=1001.2014.3001.5501


       3.构造器的定义格式 :

访问权限修饰符     构造方法名参数列表){

       //        

       //方法体

       //

}

               Δ补充说明 :              

               对于“(参数列表)” 而言,如果构造器在定义时参数列表为空,我们称它为空参构造(也叫无参构造),否则称之为带参构造(也叫有参构造。        

              方法体中的语句往往要么就是使用了this关键字的赋值语句就像我们的setter方法一样),要么就是对传入参数的校验和筛选(这个我们会在构造器的改进中讲到)。至于构造器这里为什么要使用this关键字? 这个我们在讲setter和getter方法时已经给大家说过啦,这里不再赘述,有不理解的小伙伴儿可以再回去setter,getter方法那里重新仔细看看。  

       4.构造器需要满足的要求:

       Δ构造方法名必须与类名相同!(包括大小写)

       Δ构造方法没有返回值!(但是也可以在方法内部写一个return)

       Δ构造方法没有返回值类型!因此定义构造器时千万不要写返回值类型,连void都不可以写!这一点容易和普通方法混淆!(连返回值都没有,哪儿来的返回值类型)

      5.注意事项重要):

               当类中没有定义任何构造器时,该类默认隐含一个无参构造。这也是为什么我们之前写过的类中没有定义构造器,却依然可以创建该类的对象,因为系统默认给出了无参构造,所以就会以默认的无参构造对新对象进行初始化。

               Δ但要注意:若类中已经提供了任意的构造器,那么系统不会再提供任何无参构造。啥意思呢?就是说,如果我在某个类中自定义了一个无参构造,或者自定义了一个有参构造,或者我两个都定义了,那么初始化本类对象就只能用你定义的构造器,此时不再有系统默认的空参构造器了。这一点也很重要,比如,如果我们在某个类中仅仅定义了带参构造器,那么初始化本类对象时,是不可以用空参构造的。                  

               构造器可以重载,就和方法一样,同一个类中可以定义多个构造器。至于方法的重载我们之前已经讲过了,在此不再赘述,只需要记得重载是方法名相同参数列表不同就🆗了。

               构造器是在执行new关键字的时候,由系统来完成的,即在创建对象时,系统会自动匹配并调用该类的某个构造器完成对对象的初始化。PS:其实一个对象的初始化需要三个步骤,分别是默认初始化显式初始化构造器初始化,这一点我们在Java创建对象的内存图解那里已经讲过了,我再次把链接放一下 :

https://blog.csdn.net/TYRA9/article/details/128508466?spm=1001.2014.3001.5501


       6.代码演示 :

               我们以KunKun类作为要实例化的类,以TestKunKun类作为测试类,

               我们先不定义构造器,测试一下是否能成功创建对象。    

               KunKun类代码如下 :    

packageknowledge.constructor;
publicclassKunKun {
//成员变量(KunKun类的属性)privateStringname;    //不对name进行显式初始化privateintage=11;   //对age进行显式初始化  //这里是构造器,但是我们现在先暂时什么都不写。//name和age的getter,setter方法 :publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
}

image.gif

               TestKunKun类代码如下 :

packageknowledge.constructor;
publicclassTestKunKun {
publicstaticvoidmain(String[] args) {
//1.测试系统默认提供的空参构造KunKunkun1=newKunKun();
//使用空参构造构造初始化对象,除非属性值有显式初始化,否则均为默认值。System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
//使用setter方法修改kun1对象的属性,并重新打印kun1.setName("坤哥");
kun1.setAge(18);
System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
    }
}

image.gif

               输出结果 :

image.png

               首先,我们在TestKunKun类创建KunKun对象时,IDEA并没有报错,因此可以确定系统提供了无参构造。通过输出结果,我们发现,如果未对成员变量进行显式初始化,也没有通过setter方法修改成员变量的值,输出成员变量就是它的默认值,比如此处的name属性,一开始输出name就是默认值null,而age在定义时进行了显式初始化,因此一开始输出age的结果不是默认值0。当然,通过setter方法修改属性值后,name和age的值都发生了变化。                    

               下一步,我们定义一个自己的无参构造

               因为系统默认给的无参构造里面啥都没有,就是能让你初始化对象就完了😂,你也别嫌弃,就像是免费给你的东西,要什么🚲呀。但是总得让大家看看所谓自定义无参构造是怎么一回事儿😋。好滴,我们在无参构造中输出一句话,当无参构造被调用成功时给出我们提示

               KunKun类代码如下 :

packageknowledge.constructor;
publicclassKunKun {
//成员变量(KunKun类的属性)privateStringname;
privateintage=11;
//公有的空参构造   (重点)publicKunKun() {
System.out.println("这是空参构造,成功调用此构造时打印这句话");
    }
//name和age的getter,setter方法 :publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
}

image.gif

                TestKunKun类代码如下:

packageknowledge.constructor;
publicclassTestKunKun {
publicstaticvoidmain(String[] args) {
//1.测试我们自定义的的空参构造(注意这里变了哦)KunKunkun1=newKunKun();
//使用空参构造构造初始化对象,除非属性值有显式初始化,否则均为默认值。System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
//使用setter方法修改kun1对象的属性,并重新打印kun1.setName("坤哥");
kun1.setAge(18);
System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
    }
}

image.gif

               输出结果 :

image.png

               输出后我们发现, 我们定义的无参构造成功被调用,且提示语句也成功输出,👌。

               ③第三步,我们建立一个有参构造,

               并且把刚刚建立的无参构造暂时注释掉,即,测试KunKun类仅含一个有参构造的情况KunKun类代码如下 :

packageknowledge.constructor;
publicclassKunKun {
//成员变量(KunKun类的属性)privateStringname;
privateintage=11;
//公有的带参构造   (重点)publicKunKun(Stringname, intage) {
System.out.println("这句话打印出来,说明带参构造被成功调用");
this.name=name;
this.age=age;
    }
//name和age的getter,setter方法 :publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
}

image.gif

               TestKunKun类代码如下 :

packageknowledge.constructor;
publicclassTestKunKun {
publicstaticvoidmain(String[] args) {
//2.测试带参构造KunKunkun2=newKunKun("两年半", 18);
/*使用带参构造可以使我们免去用setter方法赋值的步骤,而是可以直接修改kun2对象中对应的属性值*/System.out.println("Kun2叫啥名儿 :"+kun2.getName());
System.out.println("Kun2几岁啦 :"+kun2.getName());
System.out.println("-------------------------------------------");
    }
}

image.gif

               输出结果 :

image.png    

               可以看到带参构造成功被调用了捏🤗 。

               ④在仅含一个带参构造的前提下,测试空参构造:

               但这时候,IDEA直接给我们报错了,如下图所示 :

image.png

              IDEA提示我们不能使用空参构造来初始化KunKun类对象,这也很好解释,你**在KunKun类中就只定义了一个带参构造,根据上面的注意事项1,当我们自定义任何一个构造器后,系统就不会在提供默认的无参构造了。而你这里又想用无参构造,所以才报错。那我们怎么办呢?很简单,你有参和无参都定义一个⑧就⭐了!😎

               ⑤同时定义了无参构造和有参构造:

               KunKun类代码如下 :

packageknowledge.constructor;
publicclassKunKun {
//成员变量(KunKun类的属性)privateStringname;
privateintage=11;
//公有的空参构造   (重点)publicKunKun() {
System.out.println("这是空参构造,成功调用此构造时打印这句话");
    }
//公有的带参构造   (重点)publicKunKun(Stringname, intage) {
System.out.println("这句话打印出来,说明带参构造被成功调用");
this.name=name;
this.age=age;
    }
//name和age的getter,setter方法 :publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
//KunKun类中的成员方法(KunKun类的行为)/*复习一下我们的private关键字和this关键字,此处唱、跳、rap,篮球四个方法,均为私有,但是我们可以通过新建一个public公共方法,然后通过this关键字来分别调用这几个私有方法。*/privatevoidsing() {   //唱方法System.out.println("🐔你太美~~🐔你实在是太美~");
    }
privatevoidjump() {   //跳方法System.out.println("哎哟你干嘛~");
    }
privatevoidrap() {    //rap方法System.out.println("你Kun哥厉不厉害?");
    }
privatevoidbasketball() { //篮球方法System.out.println("🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀");
    }
//通过this关键字来调用本类对象的私有方法publicvoidpersonalTrainee() {
System.out.println("我会唱跳rap篮球!");
this.sing();
this.jump();
this.rap();
this.basketball();
    }
}

image.gif

               TestKunKun类代码如下 :

packageknowledge.constructor;
publicclassTestKunKun {
publicstaticvoidmain(String[] args) {
//1.测试我们自定义的的空参构造(注意这里变了哦)KunKunkun1=newKunKun();
//使用空参构造构造初始化对象,除非属性值有显式初始化,否则均为默认值。System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
//使用setter方法修改kun1对象的属性,并重新打印kun1.setName("坤哥");
kun1.setAge(18);
System.out.println("kun1的名字是:"+kun1.getName());
System.out.println("kun1的年龄是:"+kun1.getAge());
System.out.println("-------------------------------------------");
//2.测试带参构造KunKunkun2=newKunKun("两年半", 18);
/*使用带参构造可以使我们免去用setter方法赋值的步骤,而是可以直接修改kun2对象中对应的属性值*/System.out.println("Kun2叫啥名儿 :"+kun2.getName());
System.out.println("Kun2几岁啦 :"+kun2.getName());
System.out.println("-------------------------------------------");
//3.测试成员方法kun1.personalTrainee();
    }
}

image.gif

               输出结果 :

image.png

               同时定义有参构造和无参构造,我们就可以想调用哪个调用哪个。

               因此:系统默认有一个无参构造。 但如果类只定义了一个带参构造,则无法再使用默认的空参构造,除非在类中再显式地定义一个空参构造。 其实,我们后面的JavaBean类就会讲到,标准的JavaBean类往往就是需要空参构造和带参构造同时都要有的。

       7.关于javap命令(了解即可) :

               ①介绍 :

                       1>我们知道,java程序的运行原理是 : 我们先写好___.java的源文件,经过javac.exe命令可以将___.java的源文件编译为___.class的字节码文件,然后再由java.exe命令运行字节码文件,打印出结果。如下图所示 :

 image.png

                       2>而我们的javap命令可以理解为将“编译”这一过程给反过来了。javap是JDK提供的一个命令行工具,javap能对给定的class文件的字节代码进行反编译通过javap,我们可以对照源代码和字节码,从而了解许多编译器内部的工作,对更深入地理解如何提高程序执行的效率等问题有极大的帮助。

               ②位置 :

                       javap命令位于JDK安装目录的bin目录下。如下图:

image.png

               ③图示 :

image.png

               ④使用格式 :

                      java  <options>  <classes>        

                       其中:

                       options表示操作符,不同的操作符可以实现不同的功能,也可以不写操作符.

                       classes表示类名,就以KunKun类为栗,你可以写javap KunKun.class, 也可以写成javap KunKun,意思就是字节码文件的后缀名“.class”可以不写。                                        

               ⑤常用指令 :

                      javap -version     查看当前JDK的版本信息

                       javap -v                 输出附加信息(一大堆,啥都有,你现在也看不懂,了解即可)

                      javap -l                  输出行号和本地变量表(解释 : 同-v)

                      javap -public        仅显示公共类和成员

                       javap -protected   显示受保护的公共类和成员

                      javap -package     显示程序包受保护的公共类和成员(默认)

                      javap -private        显示所有类和成员

                       javap -c                 对代码进行反汇编

                      javap -s                  输出内部类型签名

                       javap -sysinfo       显示正在处理的类

               ⑥代码演示,javap命令演示 :

                       我们以KunKun类为栗,试试通过javap命令对KunKun类反编译会发生什么,

                       KunKun类代码如下 :

packageknowledge.constructor;
publicclassKunKun {
//成员变量(KunKun类的属性)privateStringname;
privateintage=11;
//公有的空参构造   (重点)publicKunKun() {
System.out.println("这是空参构造,成功调用此构造时打印这句话");
    }
//公有的带参构造   (重点)publicKunKun(Stringname, intage) {
System.out.println("这句话打印出来,说明带参构造被成功调用");
this.name=name;
this.age=age;
    }
//name和age的getter,setter方法 :publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
this.name=name;
    }
publicintgetAge() {
returnage;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
//KunKun类中的成员方法(KunKun类的行为)privatevoidsing() {   //唱方法System.out.println("🐔你太美~~🐔你实在是太美~");
    }
privatevoidjump() {   //跳方法System.out.println("哎哟你干嘛~");
    }
privatevoidrap() {    //rap方法System.out.println("你Kun哥厉不厉害?");
    }
privatevoidbasketball() { //篮球方法System.out.println("🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀🏀");
    }
//通过this关键字来调用本类对象的私有方法publicvoidpersonalTrainee() {
System.out.println("我会唱跳rap篮球!");
this.sing();
this.jump();
this.rap();
this.basketball();
    }
}

image.gif

               其实就是刚才测试构造器时KunKun类的最终形态。这时候,我们需要找到KunKun类的字节码文件所在的位置,字节码文件统一放在out目录下(src是存放源代码的目录), 如下图 :

image.png

               然后我们进入cmd, 通过DOS命令进入该目录,或者直接先找到该目录,然后在地址栏输入cmd回车,如下gif图 :

image.png

               🆗,接下来我们进行演示 : 如下GIF图所示 :

image.png

               可以看到,KunKun类中的空参构造和带参构造,以及所有的public方法全都显示出来了,但没有私有方法,如果要查看私有方法,需要加命令操作符 -p或者-private,如下GIF

image.png

       8.构造器的改进(🐂🖊) :

               说是构造器的改进,其实,就是针对带参构造😂。以往我们在带参构造中会写啥呢,无非就是诸如this.xxx = xxx;的语句。But,现在我们可以不写这些this关键字的语句了,肯定会有p小将(personable 小将,指风度翩翩的人来问了,你**不用this关键字你怎么把传入的值赋值给成员变量呢

               p小将你先别急。仔细想想,除了带参构造,哪里经常见到this关键字呢?没错,setter方法里面!所以,我猜你已经猜到了,我们可以利用调用setter方法的语句来代替this语句原理 : 其实,平时我们写的带参构造,无非就是把所有setter方法里面的this语句合在一起了,所以调用带参构造就可以省去调用setter方法的步骤。而现在我们要做的,就是返璞归真,在带参构造里面调用指定的setter方法,来定义指定的构造器。

               可是,为什么我们要这么做呢?

image.png

                别忘了我们的标题,啥?优化呀!说白了我们是要在setter方法里面做点手脚,让它在带参构造中发挥一些我们希望的作用效果,比如说对传入参数的校验和修正,从而实现带参构造的升级优化。

               eg : 我们创建了一个Phone类(手机类),通过实例化Phone类来模拟我要买一个新手机。因为大部分人买手机多少都抱着自己的期待和要求,比如想购买某品牌的某款手机。就拿up来说,我想买的是Huawei品牌的手机,因此实例化Phone类时,传入的brand参数必须是Huawei,不是就发出提示;up不想买旧款,因此up想买的是发售年限小于等于一年的Huawei品牌的手机,如果传入的outYear参数大于1,就发出提示;up有钱,要买的手机不想低于10000块钱,因此,如果传入的price参数小于等于10000,就发出提示

               根据上面的要求,我们可以写代码了,

               Phone类代码如下 :

packageknowledge.constructor;
publicclassPhone {
privateStringname;
privateintoutYear;
privatedoubleprice;
publicPhone() {
    }
publicPhone(Stringname, intoutYear, doubleprice) {
//        this.name = name;//        this.outYear = outYear;//        this.price = price;setName(name);
setOutYear(outYear);
setPrice(price);
    }
publicStringgetName() {
returnname;
    }
publicvoidsetName(Stringname) {
if ("Huawei".equals(name)) {
this.name=name;
        } else {
System.out.println("姐,我要买的是Huawei手机。");
        }
    }
publicintgetOutYear() {
returnoutYear;
    }
publicvoidsetOutYear(intoutYear) {
if (1>=outYear) {
this.outYear=outYear;
        } else {
System.out.println("姐,我想要的是新款。");
        }
    }
publicdoublegetPrice() {
returnprice;
    }
publicvoidsetPrice(doubleprice) {
if (10000<price) {
this.price=price;
        } else {
System.out.println("👴刚发了奖金,不差钱!");
        }
    }
}

image.gif

               接着,我们再创建一个TestPhone类,用来测试Phone类,TestPhone类代码如下

packageknowledge.constructor;
publicclassTestPhone {
publicstaticvoidmain(String[] args) {
//1.我们先实例化一个不是Huawei品牌的手机Phonephone=newPhone("Apple", 1, 19999);
System.out.println("--------------------------------------------");
//2.再来实例化一个发售年限超过1年的Huawei品牌的手机Phonephone2=newPhone("Huawei", 3, 12999);
System.out.println("--------------------------------------------");
//3.再来实例化一个价格低于10000的,发售年限1年内的Huawei品牌手机Phonephone3=newPhone("Huawei", 1, 3699);
System.out.println("--------------------------------------------");
//4.最后实例化一个我们想买的,符合我们条件的手机PhonephoneEX=newPhone("Huawei", 1, 13999);
if ("Huawei".equals(phoneEX.getName()) &&1>=phoneEX.getOutYear() &&10000<phoneEX.getPrice()) {
System.out.println("是👴要买的手机😁");
        }
    }
}

image.gif

               输出结果 :

image.png

六、标准代码JavaBean!(编程之美

      1.Java语言编写类的标准规范 :

               JavaBean是一种特殊的Java类,是Java语言编写类的标准规范,也是最美的Java类。

               ①符合JavaBean标准的类,必须是具体,公共的;

               ②并且不但具有空参构造,通常也需要写出它的带参构造;

               ③成员变量全部用private关键字修饰,并且要提供用来操作这些成员变量的setter和getter方法。

               当JavaBean类写多了你会发现:代码越看越顺眼,美观大方,整洁优雅,反正up现在一看到符合JavaBean类的代码,都会很欣慰😂。

       2.标准JavaBean类代码演示 :

               以Student2类为演示类,Student2类代码如下

packageknowledge.define.student;
//这就是一个标准的javaBean类publicclassStudent2 {
//无参构造:publicStudent2() { }
//带参构造:publicStudent2(Stringname, intage, Stringsex) {
this.name=name;
this.age=age;
this.sex=sex;
    }
//成员变量privateStringname;
privateintage;
privateStringsex;
//成员变量的setter和getter方法。publicvoidsetName(Stringname) {
this.name=name;
    }
publicStringgetName() {
returnname;
    }
publicvoidsetAge(intage) {
this.age=age;
    }
publicintgetAge() {
returnage;
    }
publicStringgetSex() {
returnsex;
    }
publicvoidsetSex(Stringsex) {
this.sex=sex;
    }
}
/** Summary:*    1.只要你写了一个任意形式的构造体,那么系统就不会给默认的无参构造了*    2.所以一般定义类用到构造体时,无参和有参形式都需要手动写上。*    3.注意setter函数返回值类型均为void,而getter函数的返回值类型取决于该getter函数对应的*       setter函数的形参类型。* */

image.gif

              TestStudent类代码如下

packageknowledge.define.student;
publicclassTestStudent2 {
publicstaticvoidmain(String[] args) {
//需求一: 定义一个姓名为Cyan,年龄为19的学生//格式一: 通过无参构造实现:Student2student2=newStudent2();
student2.setName("Cyan");
student2.setAge(19);
student2.setSex("male");
System.out.println(student2.getName());
System.out.println(student2.getAge());
System.out.println(student2.getSex());
System.out.println("-------------------");
//格式二: 通过构造方法快速初始化:Student2st2=newStudent2("Cyan", 19, "男");
System.out.println(st2.getName());
System.out.println(st2.getAge());
System.out.println(st2.getSex());
    }
}

image.gif

              输出结果 :

image.png

七、总结 :

               🆗,费了这么大功夫总算是把面向对象三个特性的第一关BOSS给干掉了😄。回顾一下,我们从封装的引入开始,到private关键字this关键字,以及构造器,中间这三个都很详细得做了讲解,最后我们又说到了JavaBean。好滴,感谢阅读!

System.out.println("END------------------------------------------------------------");          

目录
相关文章
|
18天前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
45 2
|
19天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
33 3
|
19天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
31 2
|
21天前
|
存储 算法 Java
Java Set因其“无重复”特性在集合框架中独树一帜
【10月更文挑战第14天】Java Set因其“无重复”特性在集合框架中独树一帜。本文深入解析Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定的数据结构(哈希表、红黑树)确保元素唯一性,并提供最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的`hashCode()`与`equals()`方法。
27 3
|
25天前
|
安全 Java API
Java 17新特性让你的代码起飞!
【10月更文挑战第4天】自Java 8发布以来,Java语言经历了多次重大更新,每一次都引入了令人兴奋的新特性,极大地提升了开发效率和代码质量。本文将带你从Java 8一路走到Java 17,探索那些能让你的代码起飞的关键特性。
70 1
|
1月前
|
编解码 Oracle Java
java9到java17的新特性学习--github新项目
本文宣布了一个名为"JavaLearnNote"的新GitHub项目,该项目旨在帮助Java开发者深入理解和掌握从Java 9到Java 17的每个版本的关键新特性,并通过实战演示、社区支持和持续更新来促进学习。
70 3
|
1天前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
10 4
|
10天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
10 2
|
16天前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
38 3
|
16天前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
23 2