java类成员/final/static都涉及到了2023025

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

类成员
在Java类里只能包含成员变量、方法、构造器、初始化块、内部类包括接口、枚举这5种成员目前已经介绍了前面4种其中static可以修饰成员变量、方法、初始化块、内部类包括接口枚举以static修饰的成员就是类成员。类成员属于整个类而不属于单个对象。
类变量属于整个类当系统第一次准备使用该类时系统会为该类变量分配内存空间类变量开始生效直到该类被卸载该类的类变量所占有的内存才被系统的垃圾回收机制回收。类变量生存范围几乎等同于该类的生存范围。当类初始化完成后类变量也被初始化完成。
类变量既可通过类来访问也可通过类的对象来访问。但通过类的对象来访问类变量时实际上并不是访问该对象所拥有的变量因 为当系统创建该类的对象时系统不会再为类变量分配内存也不会再次对类变量进行初始化也就是说对象根本不拥有对应类的类变量。通过对象访问类变量只是一种假象通过对象访问的依然是该类的类变量可以这样理解当通过对象来访问类变量时系统会在底层转换为通过该类来访问类变量。
提示
很多语言都不允许通过对象访问类变量对象只能访问实例变量类变量必须通过类来访问。
由于对象实际上并不持有类变量类变量是由该类持有的同一个类的所有对象访问类变量时实际上访问的都是该类所持有的变量。因此从程序运行表面来看即可看到同一类的所有实例的类变量共享同一块内存区。类方法也是类成员的一种类方法也是属于类的通常直接使用类作为调用者来调用类方法但也可以使用对象来调用类方法。与类变量类似即使使用对象来调用类方法其效果也与采用类来调用类方法完全一样。
当使用实例来访问类成员时实际上依然是委托给该类来访问类成员因此即使某个实例为null它也可以访问它所属类的类成员。
空指针怎么来的
如果一个null对象访问实例成员包括实例变量和实例方法将会引发NullPointerException异常因为null表明该实例根本不存在既然实例不存在那么它的实例变量和实例方法自然也不存在。
类初始化块静态初始化块也是类成员的一种类初始化块用于执行类初始化动作在类的初始化阶段系统会调用该类的类初始化块来对类进行初始化。一旦该类初始化结束后类初始化块将永远不会获得执行的机会。
对static关键字而言有一条非常重要的规则类成员包括成 员变量、方法、初始化块、内部类和内部枚举不能访问实例成员 包括成员变量、方法、初始化块、内部类和内部枚举。因为类成员是属于类的类成员的作用域比实例成员的作用域更大完全可能出现类成员已经初始化完成但实例成员还不曾初始化的情况如果允许类成员访问实例成员将会引起大量错误。

static的一个重要应用单例类单例类又是什么呢
单例Singleton类
大部分时候都把类的构造器定义成public访问权限允许任何类自由创建该类的对象。但在某些时候允许其他类自由创建该类的对象没有任何意义还可能造成系统性能下降因为频繁地创建对象、 回收对象带来的系统开销问题。
例如系统可能只有一个窗口管理器、一个假脱机打印设备或一个数据库引擎访问点此时如果在系统中为这些类创建多个对象就没有太大的实际意义。
如果一个类始终只能创建一个实例则这个类被称为单例类。
总之在一些特殊场景下要求不允许自由创建该类的对象而只允许为该类创建一个对象。为了避免其他类自由创建该类的实例 应该把该类的构造器使用private修饰从而把该类的所有构造器隐藏起来。
根据良好封装的原则一旦把该类的构造器隐藏起来就需要提供一个public方法作为该类的访问点用于创建该类的对象且该方法必须使用static修饰因为调用该方法之前还不存在对象因此调用该方法的不可能是对象只能是类。
除此之外该类还必须缓存已经创建的对象否则该类无法知道是否曾经创建过对象也就无法保证只创建一个对象。为此该类需要使用一个成员变量来保存曾经创建的对象因为该成员变量需要被上面的静态方法访问故该成员变量必须使用static修饰。
在这里插入图片描述
final修饰符
final关键字可用于修饰类、变量和方法用于表示它修饰的类、方法和变量不可改变。
final修饰变量时表示该变量一旦获得了初始值就不可被改变
final既可以修饰成员变量包括类变量和实例变量也可以修饰局部变量、形参。
有的书上介绍说final修饰的变量不能被赋值这种说法是错误的严格的说法是final修饰的变量不可被改变一旦获得了初始值该final变量的值就不能被重新赋值。由于final变量获得初始值之后不能被重新赋值因此final修饰成员变量和修饰局部变量时有一定的不同。
成员变量是随类初始化或对象初始化而初始化的。当类初始化时系统会为该类的类变量分配内存并分配默认值当创建对象时系统会为该对象的实例变量分配内存并分配默认值。也就是说当执行静态初始化块时可以对类变量赋初始值当执行普通初始化块、构造器时可对实例变量赋初始值。因此成员变量的初始值可以在定义该变量时指定默认值也可以在初始化块、构造器中指定初始值。
对于final修饰的成员变量而言一旦有了初始值就不能被重新赋值如果既没有在定义成员变量时指定初始值也没有在初始化块、构造器中为成员变量指定初始值那么这些成员变量的值将一直是系统默认分配的0、‘\u0000’、false或null这些成员变量也就完全失去了存在的意义。因此Java语法规定final修饰的成员变量必须由程序员显式地指定初始值归纳起来final修饰的类变量、实例变量能指定初始值的地方如下。
1.类变量必须在静态初始化块中指定初始值或声明该类变量时指定初始值而且只能在两个地方的其中之一指定。
2.实例变量必须在非静态初始化块、声明该实例变量或构造器中指定初始值而且只能在三个地方的其中之一指定。但需要注意的是如果普通初始化块已经为某个实例变量指定了初始值则不能再在构造器中为该实例变量指定初始值

final修饰局部变量又回怎样呢
系统不会对局部变量进行初始化局部变量必须由程序员显式初始化。因此使用final修饰局部变量时既可以在定义时指定默认值也可以不指定默认值。
如果final修饰的局部变量在定义时没有指定默认值则可以在后面代码中对该final变量赋初始值但只能一次不能重复赋值如果final修饰的局部变量在定义时已经指定默认值则后面代码中不能再对该变量赋值。下面程序示范了final修饰局部变量、形参的情形。
在这里插入图片描述

final修饰基本类型变量和引用类型变量的区别
当使用final修饰基本类型变量时不能对基本类型变量重新赋值因此基本类型变量不能被改变。但对于引用类型变量而言它保存的仅仅是一个引用final只保证这个引用类型变量所引用的地址不会改变即一直引用同一个对象但这个对象完全可以发生改变。

引申出宏变量
Java会使用常量池来管理曾经用过的字符串直接量例如执行var a=“java”语句之后常量池中就会缓存一个字符串"java"如果程序再次执行var b=“java”;系统将会让b直接指向常量池中的"java"字符串因此a==b将会返回true。
还有一种场景
在这里插入图片描述
final修饰方法是什么样呢
final修饰的方法不可被重写如果出于某些原因不希望子类重写父类的某个方法则可以使用final修饰该方法。Java提供的Object类里就有一个final方法getClass()因为
Java不希望任何类重写这个方法所以使用final把这个方法密封起来。但对于该类提供的toString()和equals()方法都允许子类重写因此没有使用final修饰它们。final修饰的方法仅仅是不能被重写是可以重载的。但是也知道重载一半时在一个类里做的相当于两个不同的方法。
注意事项private修饰的方法是可以在子类中加final的private final sss(){},为啥呢
对于一个private修饰的方法它仅在当前类中可见其子类无法访问该方法所以子类无法重写该方法—如果子类中定义一个与父类private方法有相同方法名、相同形参列表、相同返回值类型的方法 也不是方法重写只是重新定义了一个新方法。也就是说子类中的同名方法和父类中的没有毛线关系那在子类中使用final修饰一个private访问权限的方法一点毛病没有依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法。

更进一步final修饰类怎么办
final修饰的类不可以有子类例如java.lang.Math类就是一个final类它不可以有子类。
当子类继承父类时将可以访问到父类内部数据并可通过重写父类方法来改变父类方法的实现细节这可能导致一些不安全的因素。为了保证某个类不可被继承则可以使用final修饰这个类。
那么final修饰就是不可变类了不完全还有其他要求
不可变immutable类的意思是创建该类的实例后该实例的实例变量是不可改变的。Java提供的8个包装类和java.lang.String类都是不可变类当创建它们的实例后其实例的实例变量不可改变。
如果需要创建自定义的不可变类可遵守如下规则。
1.使用private和final修饰符来修饰该类的成员变量。且的关系
2.提供带参数的构造器或返回该实例的类方法用于根据传入参数来初始化类里的成员变量。
3.仅为该类的成员变量提供getter方法不要为该类的成员变量提供setter方法因为普通方法无法修改final修饰的成员变量。
4.如果有必要重写Object类的hashCode()和equals()方法。equals()方法根据关键成员变量来作为两个对象是否相等的标准除此之外还应该保证两个用equals()方法判断为相等的对象的hashCode()也相等。
例如java.lang.String这个类就做得很好它就是根据String对象里的字符序列来作为相等的标准其hashCode()方法也是根据字符序列计算得到的。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java