10_星仔带你学Java之深入变量以及Java的封装思想

大家好,我是💖星仔💖。一个致力于为大家分享各种Java知识的博主。

✨专栏汇总✨

        🍋《星仔带你部署银河麒麟RAM架构服务器》

        🍋《星仔带你学消息队列(RebbitMQ)》

        🍋《星仔带你学Java》

        🍋《星仔带你学Elasticsearch》

        🍋《星仔带你搞定Java开发小技巧》

        🍋《星仔带你学Java设计模式》

        🍋《星仔带你搞定【软考-系统架构设计师】》

        🍋《星仔带你玩转Java面试》

    本博客收录于《华星详谈-学习中心》。本学习中心收集了Java整个技术体系的所有技术要点。每篇博客后面或者知识点结尾都附带有面试题,提供给大家巩固本章内容。

为各位同胞们能够系统性的掌握整个Java技术体系而建立的学习中心。星仔正在努力的更新学习中心中的内容。望诸君共勉!!!

🍋一、深入变量

定义变量的语法:

  数据类型  变量名 = ;

🍒1.1 变量的分类和初始值

变量根据在类中定义位置的不同,分成两大类:

成员变量全局变量/字段(Field),不要称之为属性(错误)。  直接定义在类中,方法外面。

                       1):类成员变量          使用static修饰的字段;

                       2):实例成员变量      没有使用static修饰的字段;

局部变量变量除了成员变量,其他都是局部变量。

                       1):方法内部的变量;

                       2):方法的形参;

                       3):代码块中的变量,一对{};

class   ABC {

          String info = null;//成员变量

          void  doWork(String name){

                  System.out.println(x);

                  int age;//局部变量

                  if(true) {

                            int  num;//局部变量

                    }

           }

            {

                            int  num;//局部变量

            }

            String  x ;

}

变量的初始值初始化才会在内存中开辟空间。

成员变量:   默认是有初始值的

局部变量:   没有初始值,所以必须先初始化才能使用

🍒1.2 变量的作用域和生命周期

1.2.1 变量的作用域:

    变量根据定义的位置不同,决定了各自的作用域是不同的。看变量所在的那对{}

成员变量:在整个类中都有效;

局部变量::在开始定义的位置开始,到紧跟着结束的花括号为止;

成员变量可以先使用后定义,局部变量必须先定义而后才能使用。

1.2.2 变量的生命周期:

        变量的作用域指的是变量的存在范围,只有在这个范围内,程序代码才能访问它。当一个变量被定义时,它的作用域就确定了

        变量的作用域决定了变量的生命周期,说明作用域不同,生命周期就不一样。变量的生命周期指的是一个变量被创建并分配内存空间开始,到该变量被销毁并清除其所占内存空间的过程。

🍒1.3 局部变量的初始化

        局部变量定义后,必须显示初始化后才能使用,因为系统不会为局部变量执行初始化操作。这就意味着,定义局部变量后,系统并未为这个变量分配内存空间。直到程序为这个变量赋值时,系统才会为局部变量分配内存,并将初始值保存到该内存中。

局部变量不属于任何类或实例,因此它总是保存在其所在方法的栈内存中

基本数据局部变量:直接把这个变量的值保存到该变量所对应的内存中。

引用数据局部变量:这个变量内存中存的是地址,通过该地址引用到该变量实际引用堆里的的对象。

栈内存中的变量无需系统垃圾回收,其往往随方法或代码块的运行结束而结束

🍒1.4 什么时候使用成员变量和局部变量

        1:考虑变量的生存时间,这会影响内存开销。

        2:扩大变量作用域,不利于提高程序的高内聚。

        开发中应该尽量缩小变量的作用范围,如此在内存中停留时间越短,性能也就更高。不要动不动就使用static修饰。一般定义工具方法的时候,static方法需要访问的变量,该变量属于类,此时才使用static修饰字段。也不要动不动就使用成员变量,因为存在着线程不安全问题,能使用局部变量尽量使用局部变量。

🍋二、Java的封装思想

🍒2.1 package语句

生活中场景

    在我的电脑硬盘的某一个文件夹中里存有1000部电影,我会在把新的电影存到该文件夹中,也可以看该文件夹中的任何电影。

    可能出现的问题/操作不便

问题1:  不能出现文件名和拓展名相同的文件。---->如何解决?

问题2:  想看片了想从1000部中找到自己现在想看的某一部,存在特别麻烦。

    解决方案:

         可以在存储电影之前,按照电影的类型分类管理。爱情/惊悚/科幻/动作/喜剧/历史/XX老师的/龙哥等。

          但是呢,即使如此分类之后也可能出现喜剧文件夹中存在500部,这时我们可以继续细分。

        由上面的例子,我们在开发中,假如存在几百上千个Java文件,如果所有的Java文件都在一个目录中,管理起来也很痛苦。此时我们可以使用生活中的解决方案,不过呢此时在Java我们把这个特殊文件夹称之为包(package)。

package:专门用来给当前Java文件设置包名。

语法格式:

package  包名.子包名.子子包

必须把该语句作为Java文件中,并且是第一行代码(所有代码之前)。

此时编译命令

javac   -d .   Hello.java;

如果此时Hello.java文件中没有使用package语句,表示在当前目录中生成字节码文件。

如果此时Hello.java文件中使用了package语句,此时表示在当前目录中先生成包名,再在包中生成字节码文件

运行命令

java   包名.类名;

示例如下:

 此时,编译命令和运行命令如下

编译命令: javac -d  .  PackageDemo.java

运行命令: java    abc.xyz.PackageDemo

package最佳实践 

1):包名如何定义。自定义的包名,不能以 java. 打头,因为Java的安全机制会检查

      a、包名必须遵循标识符规范/全部小写;

      b、企业开发中,包名一般是公司域名倒写;(package   域名倒写.模块名.组件名;)

2)类的名称

    类的简单名称:           定义类的名称PackageDemo;

    类的全限定名称:       包名.类名;         com.hxxt.hello.PackageDemo;

3):在开发中都是先有package,而后在package中再定义类。

Java(JDK)中的包名

🍒2.2 import语句

A类和B类不在同一个包中,A类需要使用到B类,此时就得让A类中去引入B类。

注意:在这里演示import的时候,因为没有学习到public的原因,我不会演示去引入自定义带package的类。

我们之前学习过数组的工具类:Arrays类,该类在java.util包中。Arrays类的全限定名:java.util.Arrays

没有使用import之前,操作不在同一个包中的类,得使用全限定名来操作

这样写的话很麻烦,也不便于阅读。解决方案就是使用import语句,直接把某个包下的类导入到当前类中

   语法格式:  import   需要导入类的全限定名;

此后在本Java文件中,只需要使用类的简单名称即可

又如以下代码片段中,同一个Java文件中引入了java.util包中不同的Java文件Arrays类、Set类、List

 

问题:如果我们还需要继续引入java.util包中其他的类,我们还得提供Nimport语句,要写很多次,很不爽。那有没有什么更方便的方式呢?

解决方案使用通配符( *

import    类的全限定名;    //只能导入某一个类

import    包名.子包名.*;   //表示会引入该包下的所有的在当前文件中使用到的类

import  java.util.*;    此时的*表示类名。

注意::编译器会默认找java.lang包下的类。但是却不会去找java.lang的子包下的类。比如:java.lang.reflect.Method类。此时我们也得使用  import java.lang.reflect.Method  来进行引入。

🍒2.3 静态导入(static import)语句

        在上述代码中,每次使用Arrays类中的静态方法,即使我们使用了import语句,但是每次都需要使用Arrays类名去调用静态方法。

我就觉得不爽。我期望:我能把Arrays类中的静态成员作为自己的静态成员一样调用。

解决方案:使用静态导出的方式

语法格式:import   static 类的全限定名.该类中的static成员名;

import  static   类的全限定名.*;   此时的*表示当前类的任意使用到的静态成员。

        我们通过反编译工具可以发现,其实所谓的静态导入也是一个语法糖(编译器级别的新特性在实际开发中我们不使用静态导入,因为如此分不清某一个静态方法或字段来源于哪一个类。

🍒2.4 理解封装

什么是封装(面向对象三大特征之一)

①、把对象的状态和行为看成一个统一的整体,将二者存放在一个独立的模块中();

②、"信息隐藏",把不需要让外界知道的信息隐藏起来,尽可能隐藏对象功能实现细节,向外暴露方法,保证外界安全访问功能;  把所有的字段使用private私有化则是不准外界访问。把方法使用public修饰则是允许外界访问。

一句话总结封装就是:把所有数据信息隐藏起来,尽可能隐藏多的功能,只向外暴露便捷的方法,以供调用

封装的好处:

1)、使调用者正确、方便的使用系统功能,防止调用者随意修改系统属性

2)、提高组件的重用性;

3)、达到组件之间的低耦合性(当某一个模块实现发生变化时,只要对外暴露的接口不变,就不会影响到其他模块);

4)、高内聚:把该模块的内部数据,功能细节隐藏在模块内部,不允许外界直接干预。

5)、低耦合:该模块只需要给外界暴露少量功能方法。

那我们是通过什么来实现隐藏和暴露功能呢?这时就不得不说访问权限修饰符的故事了。

🍒2.5 访问权限修饰符

        封装其实就是要让有些类看不到另外一些类里面做了什么事情。所以java提供了访问权限修饰符来规定在一个类里面能看到什么,能暴露什么。

访问权限控制: 

private:        表示私有的,表示类访问权限。只能在本类中访问,离开本类之后,就不能直接访问。不写(缺省):  表示包私有,表示包访问权限。 访问者的包必须和当前定义类的包相同才能访问。

protected:    表示子类访问权限,同包中的可以访问。即使不同包但是有继承关系,也可以访问。

public:          表示全局的,可以公共访问权限。如某个字段/方法使用了public修饰,则可以在当前项目中任何地方访问。

package a;
class  A
{
     private int age;//此时age只能在A类中访问
     }
}
----------------------------------------
package a.b;
class B
{
     String name;//此时name变量没有访问修饰符.
     //name只能在a.b包中访问.
}
------------------------------------
package a.b.c;
class C
{
     
}

注意:

  • 一般的字段都使用private修饰,表达隐藏,主要是为了安全性;
  • 拥有实现细节的方法,一般使用private修饰。不希望外界调用者看到该方法的实现细节
  • 一般情况下方法我们使用public修饰,供外界直接调用。
  • 一般情况下我们不用缺省,即使要使用也仅仅是暴露给同包中的其他类。

  • protected一般在继承关系中,父类需要把一个方法只暴露给子类

//直接暴露给外界,供调用者直接调用即可

public void doWork()

{

          methodA();

          methodB();

          methodC();

}

//仅仅只是完成了部分操作,不需要调用者调用

private  methodA(){}

private  methodB(){}

private  methodC(){}

🍒2.6 JavaBean规范

JavaBean规范:JavaBean 是一种JAVA语言写成的可重用组件()。

必须遵循一定的规范

       1):类必须使用public修饰;

       2):必须保证有公共无参数构造器,即使手动提供了带参数的构造器,也得提供无参数构造器;

       3):包含了属性的操作手段(给属性赋值、获取属性值);

分类

       1):复杂:UI,比如Button、Panel、Window类;

       2):简单:domain、dao、service组件、封装数据、操作数据库、逻辑运算等;

成员:方法(Method)、事件(event)、属性(property)

属性:

    1)、attribute:表示状态。Java中没有该概念,很多人把字段(Field)称之为属性(attribute)。不要把成员变量叫做属性

    2)、property::表示状态,但是不是字段。是属性的操作方法(getter/setter)决定的,框架中使用的大多是是属性。

        我们讲完封装之后说应该把对象中信息隐藏起来把类中的字段全部使用private修饰起来,其他类不能直接访问)。为了能让外界(其他类访问到本类中的私有字段成员,我们专门提供getter以及setter方法。

字段:   private  String  name;

getter方法:   仅仅用于获取某一个字段存储的值。

//去掉get,把首字母小写,得到name1.此时name1才是属性.

public    String   getName1(){

           return   name;//返回name字段存储的值

}

如果操作的字段是boolean类型的,此时不应该叫做getter方法,而是is方法。 getName 变成 isName

setter方法仅仅用于给某一个字段设置需要存储的值

public   void    setName1(String  n){

            name = n;//把传过来的n参数的值,存储到name字段中

}

每一个字段都得提供一对getter/setter。以后使用IDEA工具之后getter/setter都是自动生成。

ps:在JavaBean中有属性这个概念,只有标准情况下字段名和属性名才相同。

🍒2.7 this关键字

        this表示当前对象,主要存在于构造器和方法中。在构造器中就表示当前创建的对象;在方法中就表示哪一个对象调用this所在的方法,那么此时this就表示哪一个对象。当一个对象创建之后,JVM会分配一个引用自身的引用(this)。

使用this的好处:

        ① 解决成员变量和参数(局部变量)之间的二义性;

        ② 同类中实例方法间互调(此时可以省略this,但是不建议省略);

        ③ 将this作为参数传递给另一个方法;

        ④ 将this作为方法的返回值(链式方法编程);

        ⑤ 构造器重载的互调,this([参数])必须写在构造方法第一行

        ⑥ static不能和this一起使用;当字节码被加载进JVM时,static成员以及存在了。但是此时对象还没有创建,没有对象就没有this。

🍒2.8 构造器和setter方法选用

创建对象并给对象设置初始值有两种方式:

    方式1:先通过无参数构造器创建出一个对象,再通过对象调用相应的setter方法;

    方式2::直接调用带参数的构造器,创建出来的对象就有了初始值;

ps:通过构造器和通过setter方法都可以完成相同的功能。

给对象设置数据分为两种方式:一种是setter注入(属性注入);一种是构造器注入。

那这两种方式如何选择呢?

       1:如果存在带参数的构造器,方式2是比较简洁的;

       2:如果在构建对象的时候需要初始化多个数据,如果使用方式2,那么构造器得提供N个参数,参数过大不直观。此时使用方式1简单明了;

       3:比如圆对象,如何画圆。圆对象必须根据半径来确定对象。就应该在构建圆对象的时候,就要确定半径值。

总的来说就是如果需要根据数据来构建对象,,此时优先选用构造器方式其他时候任选。

🍒2.9 案例分析:判断点和圆的关系

练习:判断一个点和圆的关系(在圆外圆周上圆内)。

代码如下:

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

华星详谈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值