JAVA语言中的final修饰符
修饰符的作用范围

修饰符的作用范围
修饰符是编程语言中常见的概念,它可以用来限制变量、函数、类等的作用范围。
在编程中,修饰符有着重要的作用,可以帮助程序员更好地管理和控制代码,从而提高程序的可靠性和安全性。
修饰符的作用范围主要分为三个方面:访问控制、继承和多态。
其中,访问控制指的是控制外部代码对成员变量和成员函数的访问权限;继承指的是子类继承父类的属性和方法,从而扩展或修改父类的功能;多态指的是同一方法在不同对象或类中的表现形式不同。
在Java编程中,常用的修饰符包括 public、private、protected、static、final、abstract、synchronized等。
其中,public修饰的成员变量和成员函数可以被任何代码访问,private修饰的成员变量和成员函数只能在本类中被访问,protected修饰的成员变量和成员函数可以在本类和子类中被访问。
在继承中,子类可以通过使用关键字“extends”继承父类的属
性和方法。
此时,父类的修饰符对子类的作用范围也会产生影响。
如果父类的成员变量和成员函数被private修饰,那么子类将无法访问这些成员。
如果父类的成员变量和成员函数被protected修饰,那么子类可以访问这些成员。
在多态中,同一个方法可以被不同的对象或类调用,而表现形式也可能不同。
例如,在面向对象编程中,一个动物类中的eat()方法可以被不同的子类继承并重写,从而表现出不同的吃的方式。
总之,修饰符在编程中扮演着重要的角色,它可以帮助程序员更
好地管理和控制代码,从而提高程序的可靠性和安全性。
程序员应该根据实际需求选择合适的修饰符,并学会灵活运用。
java题库—判断

第一章:1、CPU指的是运算器和CRT F×2、计算机与一般计算装置的本质区别是它具有存储程序和程序控制功能T*√3、在计算机中,控制器是执行算术运算和逻辑运算的部件,它的任务是对信息进行加工处理。
×4、程序在运行时发现的错误一般是程序语法上的错误。
√*5、第一代计算机时期没有操作系统。
√6、计算机中数值数据一般采用补码形式存储。
√7、利用Java语言可以开发客户端Java小程序和应用程序,以及独立的服务器应用程序等。
√8、Java2技术分为J2EE、J2SE和J2ME,其中J2SE是Java的企业版,用来针对企业级进行应用服务的开发。
×9、Java语言适合开发跨平台的应用程序。
√10、Java语言适合用来开发系统程序,像很多的操作系统及驱动程序都是用Java来编写的。
×11、Java源程序文件扩展名必须为.java,但文件名不必与(主)类名保持一致。
×12、Java的平台无关性主要是依靠JRE实现的。
×13、与Java应用程序(Application)不同,Java Applet程序的运行,需要得到客户端浏览器的支持。
√14、安装JDK时,需要配置环境变量path、classpath和JA V A_HOME。
√第三章:1、J2EE企业版是以企业为环境而开发应用程序的解决方案。
√2、J2ME小型版是致力于消费产品和嵌入式设备的最佳解决方案。
√3、J2SE标准版为桌面开发和低端商务应用提供了可行的解决方案。
√4、Java是区分大小写的语言,关键字的大小写不能搞错,如果把类class写成Class或者CLASS,都是错误的。
√5、Java源程序编写好之后,以文件的形式保存在硬盘或U盘上,源文件的名字可以随便取的,它不一定与程序的主类名一致。
×6、在JDK命令行开发工具中,用编译程序javac.exe编译生成的文件是二进制可执行文件。
java中修饰符的限制范围

java中修饰符的限制范围Java 是一种面向对象的编程语言,其中修饰符是用于限制代码可见性、修饰类、方法、变量等的重要机制。
掌握不同修饰符的限制范围和应用场景对于Java 开发者至关重要。
一、概述Java 修饰符Java 修饰符分为以下几种:1.访问修饰符:用于控制类、方法、变量的可见性,包括public、private、protected 和默认(friendly)四种。
2.非访问修饰符:包括final、volatile、transient、static、synchronized、native、const 和volatile 等。
二、限制范围的作用访问修饰符的限制范围如下:1.public:表示公共的,可以被任何类访问,包括其他包中的类。
2.private:表示私有,只能在本类中访问。
3.protected:表示受保护,可以被以下三种情况访问:a.同一个包中的类。
b.子类(继承关系)。
c.同一个包中的静态方法。
4.default(友好访问符):表示默认访问权限,相当于protected。
可以被同一个包中的类访问,但不能被其他包中的类访问。
三、不同修饰符的应用场景1.访问修饰符:- public:适用于需要与其他类共享的类、方法或变量。
- private:适用于类的内部实现,建议将私有方法设置为final,以防止子类覆盖。
- protected:适用于需要子类继承或扩展的类、方法或变量。
- default:适用于包内访问,但不希望被其他包访问的类、方法或变量。
2.非访问修饰符:- final:表示不可变,适用于常量、方法(防止被子类覆盖)和类(表示类不可继承)。
- volatile:表示变量在多个线程之间的可见性,适用于共享变量。
- transient:表示变量在垃圾回收时的处理,适用于生命周期较短的变量。
- static:表示静态,适用于静态方法、静态变量,以及类的初始化。
- synchronized:表示同步,适用于需要线程安全的方法或代码块。
JAVA语言客观作业及判断题

Java对事件的处理是采用委托方式进行的,即将需要进行事件处理的组件委托给指定的事件处理器进行处理。
答案:正确Java程序是由若干类定义组成的,类定义包括定义类头和定义类体。
答案:正确类的修饰符有静态修饰符static、最终修饰符final、易失修饰符volatile和过度修饰符transient。
答案:错误子类拥有的成员数目大于等于父类拥有的成员数目。
答案:错误Container类的add()方法将GUI组件添加到容器中。
答案:正确Frame,Panel,Apple,Button 4种组件都属于容器组件。
答案:错误在Java中对象可以赋值,只要使用赋值号(等号)即可,相当于生成了一个各属性与赋值对象相同的新对象。
答案:错误在Java的方法中定义一个常量要用const关键字。
答案:错误一个程序里有且只能有一个公共类,它就是主类。
答案:正确最终类不能派生子类。
最终方法不能被覆盖。
答案:正确在Applet中可以调用它的drawImage()方法直接画出一幅图像。
答案:错误一个复选按钮实现的是“二选一”的结构;一个单选按钮实现的是“多选一”的结构。
答案:正确当一个方法在运行过程中产生一个异常,则这个方法会终止,但是整个程序不一定终止运行。
答案:正确当一个方法在运行过程中产生一个异常,则这个方法会终止,但是整个程序不一定终止运行。
答案:正确Final类中的属性和方法都必须被final修饰符修饰。
答案:错误接口是特殊的类,所以接口也可以继承,子接口将继承父接口的所有常量和抽象方法。
答案:正确新创建的Frame视窗对象,会自动显示在屏幕上。
答案:错误Applet可以运行在浏览器中。
答案:正确Java源程序文件应以.java为后缀名保存,文件内包含几个类的定义就编译生成几个对应的字节码文件。
答案:正确类头定义主要说明类的名字、父类名和接口名。
答案:错误为了提高效率,Java中对多次出现的用双引号括起来的字符串字面量只存储一个对象。
java中 static,final,transient,volatile,Volatile关键字的作用

缓存行非64字节宽的处理器(自行调整补充字节长度,原理一样)
共享变量不会被频繁的写。追加字节会导致CPU读取性能下降,如果共享变量写的频率很低,那么被锁的几率也很小,就没必要避免相互锁定了
Volatile无法保证原子性
volatile是一种“轻量级的锁”,它能保证锁的可见性,但不能保证锁的原子性。
由于自增操作是不具备原子性的,它包括读取变量的原始值、进行加1操作、写入工作内存。那么就是说自增操作的三个子操作可能会分割开执行,就有可能导致下面这种情况出现:
假如某个时刻变量inc的值为10,线程1对变量进行自增操作,线程1先读取了变量inc的原始值,然后线程1被阻塞了;然后线程2对变量进行自增操作,线程2也去读取变量inc的原始值,由于线程1只是对变量inc进行读取操作,而没有对变量进行修改操作,所以不会导致线程2的工作内存中缓存变量inc的缓存行无效,所以线程2会直接去主存读取inc的值,发现inc的值时10,然后进行加1操作,并把11写入工作内存,最后写入主存。
如下面的例子
public class Test {
public volatile int inc = 0;
public void increase() {
inc++;
}
public static void main(String[] args) {
追加字节优化Volatile性能
在某些情况下,通过将共享变量追加到64字节可以优化其使用性能。
在JDK 7 的并发包里,有一个队列集合类LinkedTransferQueue,它在使用volatile变量时,用一种追加字节的方式来优化队列出队和入队的性能。队里定义了两个共享结点,头结点和尾结点,都由使用了volatile的内部类定义,通过将两个共享结点的字节数增加到64字节来优化效率,具体分析如下:
Java中的final变量、final方法和final类

Java中的final变量、final⽅法和final类Java中的final变量、final⽅法和final类final变量final关键字可⽤于变量声明,⼀旦该变量被设定,就不可以再改变该变量的值。
通常,由final定义的变量为常量。
例如,在类中定义PI值,可以使⽤如下语句:final double PI=3.14;在Java中定义全局常量,通常使⽤public static final修饰,这样的常量只能在定义是被赋值。
public static final double PI_VAULE = 3.14;规范:被定义为final的常量定义时需要使⽤⼤写字母命名,并且中间使⽤下划线进⾏连接。
常量⽰例:import java.util.Random;class Test{int i = 0;}/*** 常量⽰例** @author pan_junbiao**/public class FinalData{static Random rand = new Random();private final int VALUE_1 = 9; // 声明⼀个final常量private static final int VALUE_2 = 10; // 声明⼀个final、static常量private final Test test = new Test(); // 声明⼀个final引⽤private Test test2 = new Test(); // 声明⼀个不是final的引⽤private final int[] a = { 1, 2, 3, 4, 5, 6 }; // 声明⼀个定义为final的数组private final int i4 = rand.nextInt(20);private static final int i5 = rand.nextInt(20);public String toString(){return "i4值:" + i4 + " i5值:" + i5 + " ";}public static void main(String[] args){FinalData data = new FinalData();// 报错:不能改变定义为final的常量值// data.VALUE_1 = 8;// 报错:不能改变定义为final的常量值// data.VALUE_2 = 9;// 报错:不能将定义为final的引⽤指向其他引⽤// data.test = new Test();// 正确:可以对指定为final的引⽤中的成员变量赋值data.test.i = 1;// 正确:可以将没有定义为final的引⽤指向其他引⽤data.test2 = new Test();// 报错:不能对定义为final的数组赋值// int b[] = { 7, 8, 9 };// data.a = b;// 但是final的数组中的每⼀项内容是可以改变的for (int i = 0; i < data.a.length; i++){data.a[i] = 9;}System.out.println(data);System.out.println("data2");System.out.println(new FinalData());}执⾏结果:i4值:5 i5值:8data2i4值:4 i5值:8从上述执⾏结果中可以发现i5的值是相同的。
JAVA多选题

1.break ,continue ,return 的区别及作用正确的是(ABCD )A.break 跳出现在的循环块,不再执行循环(结束当前的循环体);B.continue 跳出本次循环,继续执行下次循环(结束正在执行的循环进入下一个循环条件);C.return 程序返回,不再执行下面的代码(结束当前的方法直接返回);D.以上说法都正确;2.以下关于final关键字说法错误的是(AC)A.final是java中的修饰符,可以修饰类、接口、抽象类、方法和属性;B.final修饰的类肯定不能被继承;C.final修饰的方法不能被重载;D.final修饰的变量不允许被再次赋值;3.下面哪些不是java的简单数据类型(BC)A.short;B.Boolean;C.Double;D.float;4.以下哪四个能使用throw抛出(ABCD)A.Error;B.Throwable;C.Exception;D.RuntimeException;5.下列关于静态方法描述正确的是( AC )A.非静态方法中可以调用任何成员;B.静态方法中可以使用this和super区分成员;C.静态方法中只能调用静态成员;D.静态方法只能通过对象进行调用;6.下列关于类和接口的关系说法正确的是( ABD )A.Java中的类与类只能单继承, 可以多层继承;B.Java中的类与接口是实现关系, 一个类可以在继承一个类的同时实现多个接口;C.Java中的接口与接口属于实现关系, 只能单实现;D.Java中的接口与接口属于继承关系, 可以单继承, 也可以多继承;7.关于等待唤醒方法描述正确的是(ACD)A.wait方法调用会导致当前线程释放掉锁资源;B.notify和notifyAll方法调用会导致当前线程释放掉锁资源;C.等待和唤醒的方法,都要使用锁对象调用;D.等待和唤醒方法应该使用相同的锁对象调用;8.下列关于数组和集合描述正确的是( CD )A.数组和集合的长度都是可变的;B.数组只能存储基本数据类型,集合只能存储引用数据类型;C.数组的长度固定,集合的长度可变;D.数组可以存储基本数据类型和引用数据类型, 集合只能存储引用数据类型;9.下列关于增强for循环说法正确的是( ABD )A.增强for循环可以遍历数组也可以遍历单列集合;B.增强for循环没有索引;C.增强for遍历集合, 可以通过集合对象修改集合的长度;D.增强for的底层采用的是迭代器;10.下列关于单列集合体系说法正确的是(ABC)A.List和Set都是属于Collection的子接口;B.ArrayList类属于List接口的实现类;C.HashSet类属于Set接口的实现类;D.LinkedHashMap类属于Collection接口的实现类;11.下列属于Collections工具类中的方法有( ACD )A.shuffle() : 对单列集合进行乱序;B.remove() : 删除集合中的元素;C.sort() : 对单列集合进行排序;D.addAll() : 对单列集合批量添加元素;12.下列对于Map集合的特点说法正确的是( BC )A.所有的双列集合都是无序的;B.键不能重复,值可以重复;C.键和值是一一对应的,通过键可以找到对应的值;D.Map集合键可以重复, 但是值是唯一的;13.下列对于Map集合方法描述正确的是( BCD )A.add() : 添加元素;B.remove() : 根据键删除元素;C.keySet() : 获取键集合;D.containKey() : 判断集合是否存在指定的键;14.下列关于自动装箱和拆箱正确的是( ABCD )A.自动装箱指的是基本数据类型自动转成对应的包装类类型;B.自动拆箱指的是包装类类型自动转成对应的基本数据类型;C.Integer i = 10; // 属于自动装箱;D.Int num = new Integer(“100”); // 属于自动拆箱;15.以下哪些是运行时异常(ABCD)ng.lndexOutOfBoundsException;ng.NullPointerException;C.java.util.ConcurrentModificationException;D.java.time.format.DataTimeParseException;16.以下哪些能够保证线程安全(BC)A.单例模式;B.java.util.Hashtable;C.synchronized;D.volatile;17.以下哪些语句可以正常创建Lock对象(ABD)A.Lock lock = new ReentrantLock(true);B.Lock lock = new ReentrantLock();C.Lock lock = new Lock();D.Lock lock = new ReentrantLock(false);18.对下列运算结果,判断正确的是(AD )A.“1az098”.matches("\d[a-z]{2,8}[0-9]+")结果为true;B.“1az098”.matches("\d[a-z]{2,8}[0-9]+")结果为false;C.“张三,李四,王五,马六,”.split("[,]+").length == 1;该表达式结果返回true;D.“张三,李四,王五,马六,”.split("[,]+").length == 4;该表达式结果返回true19.String str = “We are students”; 下面说法正确的是(AC )A.str的长度是15;B.str的长度是14;C.str.indexOf(“a”)返回的结果是3;stIndexOf(“e”)返回的结果是3;20.下列逻辑表达式,值为false的是(BCD)A.“abc,bcd,def,efg,”.split("[,]+").length == 4;B.“1st456”.matches("\d[a-z&&[^et]]{2,8}[0-9]+");C.“abcdefghijklmnopqrstuvwxyz”.substring(5,26).length() == 20;D.“whatisjava”.equals(null);21.在Java语言中,下列说法正确的是:(ABD)A.StringBuffer和StringBuilder的区别在于:StringBuffer是线程安全的而StringBuilder不是;B.String是不可变对象,而StringBuffer中封装的字符串数据是可以动态改变的;C.判断两个StringBuilder对象的字符序列是否相同,可以调用其equlas方法进行比较;D.String的重写了equals方法,重写的逻辑是:字符序列相同的String对象equals方法返回true;22.关于Java8 Optional的说法正确的是(AB)A.Optional的map()方法,允许改变容器中元素类型B.Optional的filter()方法执行过滤,容器中元素不符合条件,会返回一个空容器C.orElse()方法,会创建默认对象替代容器中元素对象D.Optional.ofNullable()方法中传入空引用变量,将抛出异常23.下列关于Stream流中获取功能有哪些( ACD )A.Collection接口中的默认方法stream()生成流;B.Map接口中的默认方法stream()生成流;C.Arrays中的静态方法stream生成流;D. Stream类中of方法生成流;24.下列关于Stream流中中间功能有哪些( ABC )A.filter()方法用于对流中的数据进行过滤;B.sorted()方法将流中元素进行排序;C.limit()方法截取指定参数个数的数据D.collector()方法收集流中的数据;25.下列关于Stream流中终结功能有哪些((ABD )A.forEach()方法对流中的元素遍历;B.count()方法返回此流中的元素数;C.skip()方法跳过指定参数个数的数据;D.collector()方法收集流中的数据;26.按照学生平均成绩(avg_grade) 将students表中的数据检索出来,下面SQL语句正确的是(ACD)A.SELECT * FROM students ORDER BY avg_grade;B.SELECT * FROM students GROUP BY avg_grade ASC;C.SELECT * FROM students ORDER BY avg_grade DESC;D. SELECT * FROM students ORDER by avg_grade asc27.下列索引定义不符合规范的是(CD)A.uniq_order_idB.idx_user_ider_id_order_idD.idx_a_b_c_d_e_f28.下面有关sql 语句中delete、truncate的说法正确的是(AC)A.论清理表数据的速度,truncate一般比delete更快;B.truncate命令可以用来删除部分数据;C.truncate只删除表的数据不删除表的结构;D.delete能够回收高水位(自增ID值);29.在SQL中语法规范中,having子句的使用下面描述正确的是(AC)A.having子句即可包含聚合函数作用的字段也可包括普通的标量字段使用having的同时不能使用where子句;B.having子句必须于group by 子句同时使用,不能单独使用使用having子句的作用是限定分组条件;C.having子句和where子句是等同的;D.having子句后面必须使用聚合函数;30.下列中属于MyBatis全局配置文件中的标签是(ACD)A.settings;B.select;C.plugins;D.properties;31.在MyBatis 动态SQL 中,循环使用的标签名不正确的是(ABD)A.for;B.while;C.foreach;D.do-while;32.关于MyBatis传递数组参数的说法正确的是(ABD)A.在映射文件中取得数组值应该通过< forEach>标签;B.< forEach>标签可以应用于set、List以及数组的取值;C.传递数组的值,和多参数传值一样在映射文件中只能通过< forEach>取值;D.< forEach>标签的open和close属性用于写开始和结束标签;33.对mybatis描述有误的是(CD)A.MyBatis 是一个可以自定义SQL、存储过程和高级映射的持久层框架;B.MyBatis 的缓存分为一级缓存和二级缓存,一级缓存放在session 里面;C.Mybatis是一个全ORM(对象关系映射)框架,它内部封装了JDBC;D.MyBatis 只可以使用XML来配置和映射原生信息;34.Mybatis是如何将sql执行结果封装为目标对象并返回的(BC)A.id;B.< resultMap>标签;C.使用sql列的别名;D.resultType;35.mybaties中模糊查询like语句的写法(AD)A.select * from foo where bar like #{value}B.select * from foo where bar like #{%value%}C.select * from foo where bar like %#{value}%D.select * from foo where bar like “%”${value}"%"36.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?选择说法正确的(AB)A.不同的Xml映射文件,如果配置了namespace,那么id可以重复;B.如果没有配置namespace,那么id不能重复C.如果没有配置namespace,id能重复D.不同的Xml映射文件,如果配置了namespace,那么id不可以重复37.Mybatis的mapper接口调用时候的要求正确的是(ABC)A.Mapper接口方法名和Mapper.xml中定义的每个SQL的id相同B.Mapper接口方法的输入参数类型和mapper.xml中定义的每个sqlparameterType类型相同C.Mapper接口方法的输入输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同D.Mapper.xml文件中的namespace,就是接口的名字38.MyBatis内置类型别名有那些(AC)A._int;B.Integer;C.Int;D.String;39.Mybatis动态sql标签有哪些(ABC)A.trim;B.foreach;C.set;D.than40.实体类中的属性名和表中的字段名不一样怎么处理(AC)A.查询的sql语句中定义字段名的别名;B.不用处理;C.通过< resultMap>来映射字段名和实体类属性名;D.通过< resultType>来映射字段名和实体类属性名;41.关于MyBatis参数处理说法正确的是(BC)A.传递单个参数时,MyBatis会自动封装到Map集合中;B.传递单个参数时,MyBatis会自动进行参数的赋值;C.传递多个参数时,MyBatis会自动封装到Map集合中;D.传递多个参数时,MyBatis会自动进行参数的赋值;42.@SpringBootApplication注解是一个组合组件,下面是属于它的有(ACD)A.ConfigurationB.ControllerC.EnableAutoConfigurationpontScan43.以下哪些是SpringBoot默认支持自动装配的(ABC)A.spring-boot-starter-webB.spring-boot-starter-data-redisC.spring-boot-starter-securityD.mybatis-spring-boot-starter44.下面关于SpringBoot启动说明正确的是(BCD)A.SpringBoot项目启动就会加载bootstrap.properties文件B.SpringBoot项目启动会加载所有的在spring.factories中配置的监听器C.SpringBoot项目启动的时候会发布相关事件,从而会触发对应的监听器来完成对应的操作D.SpringBoot项目启动本质上就是Spring的初始化操作45.SpringBoot读取配置相关注解有(ABCD)A.@PropertySourceB.@ValueC.@EnvironmentD.@ConfigurationProperties46.Spring Boot 里面,可以使用以下哪几种方式来加载配置(ABCD)A.properties文件;B.YAML文件;C.系统环境变量;D.命令行参数;47.Dubbo集群提供了哪些负载均衡策略(ABCD)A.Random LoadBalance: 随机选取提供者策略,有利于动态调整提供者权重;B.RoundRobin LoadBalance: 轮循选取提供者策略;C.LeastActive LoadBalance: 最少活跃调用策略;D.ConstantHash LoadBalance: 一致性Hash 策略;48.Dubbo 核心组件有哪些(ABCD)A.Provider:暴露服务的服务提供方;B.Consumer:调用远程服务消费方;C.Registry:服务注册与发现注册中心;D.Monitor:监控中心和访问调用统计;49.下列哪些是SpringBoot数据源的配置项(ABC)A.spring.datasource.url=jdbc:mysqI://127.0.0.1:3306/news?useUnicode=true&characterEncoding=utf8;ername=root;C.spring.datasource.password=pwd;D.spring.datasource.driver-class =com.mysql.jdbc.Drive50.Spring Boot有哪些优点(BCD)A.完全没有代码生成和xml配置文件;B.使用JavaConfig有助于避免使用XML;C.避免大量的Maven导入和各种版本冲突;D.通过提供默认值快速开始开发。
final修饰基本类型和引用类型-概述说明以及解释

final修饰基本类型和引用类型-概述说明以及解释1.引言1.1 概述在Java编程语言中,我们经常会使用final关键字来修饰变量和方法。
在本篇文章中,我们将探讨final关键字在修饰基本类型和引用类型上的作用和影响。
final修饰符的主要作用是使变量或方法成为不可变的,也就是说它们的值或定义不能被修改。
对于基本类型和引用类型,final关键字的使用方式稍有不同,因此我们将分别讨论它们的不可变性和final关键字对它们的影响。
在接下来的章节中,我们将首先介绍基本类型的不可变性。
然后,我们将探讨final关键字的使用方法,包括如何声明和初始化final变量。
接着,我们将转向引用类型的不可变性,并讨论final关键字对引用类型的影响。
最后,我们将总结基本类型和引用类型的final修饰,总结各自的特点和应用场景。
同时,我们还会探讨未来可能的研究方向,以进一步深化我们对final修饰的理解。
通过本文的阅读,读者将能够全面了解final修饰基本类型和引用类型的特点和用法,进一步提升自己的Java编程能力。
让我们开始探索final 修饰的不可变性的奥秘吧!1.2文章结构1.2 文章结构本文将分为三个主要部分来探讨final关键字在修饰基本类型和引用类型时的使用和影响。
第一部分是引言,主要包括概述、文章结构和目的。
在概述中,我们将简要介绍final关键字以及其在Java中的作用。
文章结构将指导读者对文章的整体结构进行了解,以便更好地理解后续的内容。
而文章的目的则是明确我们撰写本文的目标,即探讨final修饰基本类型和引用类型的具体细节。
第二部分是正文,包含两个小节:final修饰基本类型和final修饰引用类型。
在2.1节中,我们将详细讨论final修饰基本类型的作用与特点。
首先,我们将解释基本类型的不可变性,即一旦被赋予了初值,它们将无法被修改。
接着,我们将探讨final关键字在修饰基本类型时的具体使用方法和语法规则。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
包
//对数组元素进行排序,合法 Arrays.sort(iArr); System.out.println(Arrays.toString(iArr));
//既没有指定默认值,又没有在初始化块,构造器中指定初始值,下面定义 char 属性是不合法
//final char ch;
//初始化块,要对没有指定默认值的实例属性指定初始值 {
str = "Hello";
语句非法
//定义 a 属性时,已经指琯了默认值,不能为 a 重新赋值,下面赋值
//a = 9; }
在上面程序中父类是 TestFinalMethod ,该类里定义的 test 方法是一个 final 方法,如果 其子类试图重写该方法,将会引发编译错误。
对一个 private 方法,因为它仅在当产类中可见,其子类无法访问该方法,所以子 类无法重写该方法----如果子类中定义一个与父类 private 方法有相同方法名,相同形参列表, 相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。因此即使使用 final 修饰一个 private 访问权限的方法,依然可以在其子类中定义与该方法具有相同方法名,相 同形参列表,相同返回值类型的方法。
static {
//在静态初始化块中为类属性指定初始值,全法 d = 5.6;
}
//在构造器,可对没有指定默认值,且没有在初始化块中指定初始值的实例 属性指定初值
public TestFinalVariable()
{
重新赋值
//如果初始化块中对 str 指定了初始值,构造器中不能对 final 变量
//下面赋值语句非法 //str ="java";
//定义 final 局部变量时没有指定默认值,则 d 变量可被赋值一次 final double d;
//第一次赋初始值,成功
d = 5.6;
//对 final 变量重复赋值,下面语句非法 //d = 3.4;
} }
上面程序中还写到了 final 修饰形参的情形:因为形参在调用该方法时,由系统根据传入的 参数来完成初始化,因此使用 final 修饰的形参不能被赋值。
因为 final 变量获得初始值之后不能被重新赋,因此 final 修饰成员变量和修饰局部 变量时有一定的不同:下面我将会写到有哪些方面的不同,还有就是为什么会不同。
final 修饰成员变量
成员变量是随类初始化或对象初始化而初始化的。当类初始化时,系统会为该类属 性分配内存,并分配默认值;当创建对象时,系统会为该对象的实例属性分配内存,并分配 默认值。也就是说,当执行静态初始化块时可以对类属性赋初始值,当执行普通初始块,构 造器时可对实例属性赋初始值。因此,成员变量的初始值可以在定义该变量时指定默认值, 可以在初始化块,构造器中指定初始值,否则,成员变量的初始值将是由系统自动分配的初 始值。
//设置调用对象的年龄
{
this.age= age;
}
public int getAge() {
return this.age; }
//返回调用对象的年龄
}
public class FinalReferenceTest {
public static void main(String[] args) {
修饰局部变量时既可以在定义时指定默认值,也可以不指定默认值。
如果 final 修饰的局部变量在定义时没有指定默认值,则可以在后面代码中进行对该 final 变量赋初始值,但只能一次,不能重复赋值:如果 final 修饰的局部变量在定义时已经 指定默认值,则后面代码中不能财对该变量赋值。
看代码:
public class TestFinalLocalVariable
class Person {
private int age; public Person() {}
//有参数构造器 public Person(int age) { this.age = age; }
//age 属性的 setter 和 getter 方法
public void setAge(int age)
因此当使用 final 修饰成员变量的时候,要么在定义成员变量时候指定初始值,要么
在初始化块,构造器中为成员变量赋初始值,如果在定义该成员变量时指定了默认值,则不 能在初始化块,构造器中为该属性生新赋值,归纳起来,final 修改的类属性,实例属性能 指定初始值的地方如下: 》类属性,可在静态初始化块中,声明该属性时指定初始值。
final 修饰基本类型和引用类型的区别:
当使用 final 修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不 能被改变,但对于引用类型的变量而言,它保存的仅仅是一个引用,final 只保证这个引用 所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。
看代码:
import java.util.*;
TestFinalVariable tf = new TestFinalVariable();
System.out.println(tf.a); System.out.println(tf.c);
System.out.println(tf.d);
}
}
程序编译结果:
上面程序详细示范了初始化成员变量的各种情形。
//下面语句对 P 重新赋值,非法 P= null;
从程序中可以看出,使用 final 修饰的引用类型变量不能被重新赋值,但可以改变引用型变 量所引用的内容,例如上面 iArr 变量所引用的数组对象,final 修饰后的 iArr 变量不能被重 新赋值,但 iArr 所引用数组的数组元素可以被改变。与此类似的是,P 变量也使用了 final 修饰,表明 P 变量不能被重新赋值,但 P 变量所引用 Person 对象的属性可以改变。
//对数组元素赋值,合法 iArr[2] = -8; System.out.println(Arrays.toString(iArr));
//下面语句对 iArr 重新赋值,非法 iArr = null;erson 变量,P 是一个引用变量 final Person p = new Person(45); //改变 Person 对象 的 age 属性,合法 P.setAge(23); System.out.println(p.getAge());
对于 final 修饰的成员变量而言,一旦有了初始值之后,就不能重新赋值,因此不可 以在普通方法中对成员变量重新赋值。成员变量只能在定义该成员变量时指定默认值,或者 在静态初始化块,初始化块,构造器中为成员变量指定初始值,如果既没有在定义成员变量 时指定初始值,也没有在初始化块,构造器中为成员变量指定初始值,那么这些成员变量的 值将一直是 0,\u0000,false null 这些成员变量也就失去了存在的意义。
{
public void test(final int a)
//在定义的方法中用 final 来修饰形参
{ //不能对 final 修饰的形参赋值,下面语句非法
//a = 5;
public static void main(String[] args) {
//定义 final 局部变量时指定默认值,则 str 变量无法重新赋值 final String str ="hello";
看代码: public class TestFinalMethod {
public final void test() {} }
class Sub extends TestFinalMethod {
//下面方法定义将出现编译错误,不能重写 final 方法 public void test() {} }
public static void main(String[] args) {
//下面定义了 4 个 final "宏变量" final int a = 5+2; final double b = 1.2/3; final String str = "世界"+"JAVA"; final String book = "世界 JAVA 您好"+99.0;
编译结果:
从编译结果中可以看出,程序中定义了一个 final 成员变量:age,系统不会对 age 成员变量 进行隐式初始化,所以初始化块中,就会报错。只要把定义 age 属性时的 final 修饰符去掉, 上面程序就会正确了。
final 修饰局部变量 系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化。因此使用 final
//系统不会对 final 成员属性进行默认初始化,所以此处代码将引起错误 System.out.println(age); age = 6;
System.out.println(age); }
public static void main(String[] args) {
new Test(); } }
与普通成员变量不同的是,final 成员变量(包括实例属性和类属性)必须由程序员 显式初始化,系统不会对 final 成员进行隐匿初始化。所以,如果打算在构造器,初始化块 中对 final 成员变量进行初始化,则不要在初始化之前就访问成员变量的值。
错误代码:
public class Test {
final int age; {
定下来。
//下面的 book2 变量的值因为调用了方法,所以无法在编译时被确 final Stringbook2 = "世界 JAVA 您好"+String.valueOf(99.0);