1、 解析 HashMap的底层是由数组加链表实现的,对于每一个key值,都需要计算哈希值,然后通过哈希值来确定顺序,并不是按照加入顺序来存放的,因此可以认为是无序的,但不管是有序还是无序,它都一个自己的顺序。故A错。 最开始有Hashtable,Hashtable是不允许key和value的值为空的,但后来开发者认为有时候也会有key值为空的情况,因为可以允许null为空,通过查看HashMap的源代码就知道:if(key = null) {putForNullKey(value);}; Map底层都是用key/value键值对的形式存放的
2、 解析 答案:C A,我们写java程序的时候只是设定事物的隔离级别,而不是去实现它 B,Hibernate是一个java的数据持久化框架,方便数据库的访问 C,事物隔离级别由数据库系统实现,是数据库系统本身的一个功能 D,JDBC是java database connector,也就是java访问数据库的驱动 补充: 在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别;为了解决更新丢失,脏读,不可重读(包括虚读和幻读)等问题在标准SQL规范中,定义了4个事务隔离级别,分别为未授权读取,也称为读未提交(read uncommitted);授权读取,也称为读提交(read committed);可重复读取(repeatable read);序列化(serializable). 3、 解析 答案:A short类型转为byte类型出错 a1a2结果为int类型,转为byte类型出错(数值型变量在默认情况下为Int型,byte和short型在计算时会自动转换为int型计算,结果也是int 型。所以a1a2的结果是int 型的) 4、 解析:
5、(歧义) 6、 下标越界问题:数组中有4个元素,小标范围为0~3 A: x[5-3],小标为2 √ B: x[k], k的范围0~3 √ C: x[k+5], 小标范围为5~8 越界× D: x[0], 小标为0 √
7、 Java单继承多实现,一个类只能继承一个类,但是可以实现多个接口,也可以在继承一个类的同时实现多个接口。单继承(类),多实现(接口)
8、 解析 A选项是函数重载的体现,一个类可以有多个参数列表不同的构造方法。A选项正确。
B选项,构造方法在对象被初始化时调用。B选项错误。
C选项,构造方法只能在对象被初始化时调用,不能由其他方法调用。
D选项,构造方法必须与类名相同。
9、 变量名称 字节 位数
byte 1 8
short 2 16
int 4 32
long 8 64
float 4 32
double 8 64
char 2 16
boolean 1 8
10、 答案是C 在java中,数组是一个对象, 不是一种原生类,对象所以存放在堆中,又因为数组特性,是连续的,只有C不对
11、 解析 A选项:Java基本数据类型共有八大类,这八大数据类型又可分为四小类,分别是整数类型(byte/short/int/long)、浮点类型(float、double)、字符类型(char)和布尔类型(boolean),其中并不包括String。
B选项中是C语言当中的String,Java的String虽然也是char类型的数组char[]实现的,但并不以“\0”结尾。
C选项正确,String类重写了Object类的equals()方法,使用equals()方法可以用于比较两个String是否内容一样。
D选项, char 类型的编码是Unicode 编码。
12、
- 首先,类的修饰符,都应该在class关键字之前,AB错;
- 抽象方法不能有方法体,D错。
13、 方法重载要求函数名完全相同,参数列表不同(数量,类型或位置均可),返回值类型不影响。 A和C的函数名与原来函数名不相同。 B的参数列表与原函数列表相同。
14、 \ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,“n"匹配字符"n”。“\n"匹配换行符。序列”\“匹配”“,”(“匹配”(“。 ^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与”\n"或"\r"之后的位置匹配。 $ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。
- 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。
- 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,"do(es)?“匹配"do"或"does"中的"do”。? 等效于 {0,1}。 {n} n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。 {n,} n 是非负整数。至少匹配 n 次。例如,"o{2,}“不匹配"Bob"中的"o”,而匹配"foooood"中的所有 o。"o{1,}“等效于"o+”。"o{0,}“等效于"o*”。 {n,m} m 和 n 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。‘o{0,1}’ 等效于 ‘o?’。注意:您不能将空格插入逗号和数字之间。 ? 当此字符紧随任何其他限定符(、+、?、{n}、{n,}、{n,m})之后时,匹配模式是"非贪心的"。“非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,“o+?“只匹配单个"o”,而"o+“匹配所有"o”。 . 匹配除”\r\n"之外的任何单个字符。若要匹配包括”\r\n"在内的任意字符,请使用诸如"[\s\S]“之类的模式。 (pattern) 匹配 pattern 并捕获该匹配的子表达式。可以使用 9 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用”(“或者”)“。 (?:pattern) 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,'industr(?:y|ies) 是比 ‘industry|industries’ 更经济的表达式。 (?=pattern) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?=95|98|NT|2000)’ 匹配"Windows 2000"中的"Windows”,但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 (?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,‘Windows (?!95|98|NT|2000)’ 匹配"Windows 3.1"中的 “Windows”,但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。 x|y 匹配 x 或 y。例如,‘z|food’ 匹配"z"或"food"。‘(z|f)ood’ 匹配"zood"或"food"。 [xyz] 字符集。匹配包含的任一字符。例如,“[abc]“匹配"plain"中的"a”。 [^xyz] 反向字符集。匹配未包含的任何字符。例如,”[^abc]“匹配"plain"中"p”,“l”,“i”,“n”。 [a-z] 字符范围。匹配指定范围内的任何字符。例如,“[a-z]“匹配"a"到"z"范围内的任何小写字母。 [^a-z] 反向范围字符。匹配不在指定的范围内的任何字符。例如,”[^a-z]“匹配任何不在"a"到"z"范围内的任何字符。 \b 匹配一个字边界,即字与空格间的位置。例如,“er\b"匹配"never"中的"er”,但不匹配"verb"中的"er”。 \B 非字边界匹配。“er\B"匹配"verb"中的"er”,但不匹配"never"中的"er”。 \cx 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。 \d 数字字符匹配。等效于 [0-9]。 \D 非数字字符匹配。等效于 [^0-9]。 \f 换页符匹配。等效于 \x0c 和 \cL。 \n 换行符匹配。等效于 \x0a 和 \cJ。 \r 匹配一个回车符。等效于 \x0d 和 \cM。 \s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。 \S 匹配任何非空白字符。与 [^ \f\n\r\t\v] 等效。 \t 制表符匹配。与 \x09 和 \cI 等效。 \v 垂直制表符匹配。与 \x0b 和 \cK 等效。 \w 匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]“等效。 \W 与任何非单词字符匹配。与”[^A-Za-z0-9_]“等效。 \xn 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,”\x41"匹配"A"。“\x041"与”\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。 num 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符。 n 标识一个八进制转义码或反向引用。如果 n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。 nm 标识一个八进制转义码或反向引用。如果 nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 nm 匹配八进制值 nm,其中 *n 和 m 是八进制数字 (0-7)。 \nml 当 n 是八进制数 (0-3),m 和 l 是八进制数 (0-7) 时,匹配八进制转义码 nml。 \un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (?)。
15、 解析 HashMap可以插入null的key或value,插入的时候,检查是否已经存在相同的key,如果不存在,则直接插入,如果存在,则用新的value替换旧的value,在本题中,第一条put语句,会将key/value对插入HashMap,而第二条put,因为已经存在一个key为name的项,所以会用新的value替换旧的value,因此,两条put之后,HashMap中只有一个key/value键值对。那就是(name,jack)。所以,size为1.
16、 &运算符:两个数都转为二进制,然后从两个数的最高位进行与运算,两个都为真(1),结果才为真(1),否则为假(0) 13:01101 17:10001 结果:00001,既为1
17、 18、 解析 A错误,类的实例方法是与该类的实例对象相关联的,不能直接调用,只能通过创建超类的一个实例对象,再进行调用 B错误,当父类的类方法定义为private时,对子类是不可见的,所以子类无法调用 C错误,子类具体的实例方法对父类是不可见的,所以无法直接调用, 只能通过创建子类的一个实例对象,再进行调用 D正确,实例方法可以调用自己类中的实例方法
19、(歧义) 20、 中间件是一种独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源。中间件位于客户机/ 服务器的操作系统之上,管理计算机资源和网络通讯。是连接两个独立应用程序或独立系统的软件。相连接的系统,即使它们具有不同的接口,但通过中间件相互之间仍能交换信息。执行中间件的一个关键途径是信息传递。通过中间件,应用程序可以工作于多平台或OS环境。 (简单来说,中间件并不能提高内核的效率,一般只是负责网络信息的分发处理) a,中间件位于操作系统之上,应用软件之下,而不是操作系统内核中
21、 静态方法是依据类而直接使用 普通方法,运用的是动态单分配,是根据new的类型确定对象,从而确定调用的方法; 静态方法,运用的是静态多分派,即根据静态类型确定对象,因此不是根据new的类型确定调用的方法 public class Father { public void say(){ System.out.println(“father”); } public static void action(){ System.out.println(“爸爸打儿子!”); } } public class Son extends Father{ public void say() { System.out.println(“son”); } public static void action(){ System.out.println(“打打!”); } public static void main(String[] args) { Father f=new Son(); f.say(); f.action(); } } 输出:son 爸爸打儿子! 当调用say方法执行的是Son的方法,也就是重写的say方法 而当调用action方法时,执行的是father的方法。 普通方法,运用的是动态单分配,是根据new的类型确定对象,从而确定调用的方法; 静态方法,运用的是静态多分派,即根据静态类型确定对象,因此不是根据new的类型确定调用的方法
22、 1、必须实现接口中所有的方法。 在实现类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。
2、接口实现类相当于子类,子类的访问权限是不能比父类小的。 接口中所有方法默认都是public,至于为什么要是public,原因在于如果不是public,那么只能在同个包下被实现,可访问权限就降低很多了,那么在实现类中,实现的类相当于子类,子类的访问权限是不能比父类小的,而在java中一个类如果没有权限的修饰符,默认是friendly(同一个包内的其它类才可访问),所以在实现类中一定要写public
3、实现类可以获取接口中的属性。
B 方法在类不写访问权限修饰,默认则是为default,与接口中public 不一致 C 方法的返回类型与接口不一致 D 方法必须被实现
23、 CountDownLatch : 一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。 CyclicBarrier: N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。 这样应该就清楚一点了,对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。 而对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。 CountDownLatch 是计数器, 线程完成一个就记一个, 就像 报数一样, 只不过是递减的。 而CyclicBarrier更像一个水闸, 线程执行就想水流, 在水闸处都会堵住, 等到水满(线程到齐)了, 才开始泄流。
24、 Math.floor() 表示向下取整,返回double类型 (floor—地板) Math.ceil() 表示向上取整,返回double类型 (ceil—天花板) Math.round() 四舍五入,返回int类型(如果传入的是double类型,则返回long; 如果是float 类型,则返回int)
25、 对于线程而言,start是让线程从new变成runnable。run方法才是执行体的入口。 但是在Thread中,run方法是个空方法,没有具体实现。 Bground继承了Thread,但是没有重写run方法,那么调用run方法肯定是无输出。
26、 存根类是一个类,它实现了一个接口,它的作用是:如果一个接口有很多方法,如果要实现这个接口,就要实现所有的方法。但是一个类从业务来说,可能只需要其中一两个方法。如果直接去实现这个接口,除了实现所需的方法,还要实现其他所有的无关方法。而如果通过继承存根类就实现接口,就免去了这种麻烦。 RMI 采用stubs 和 skeletons 来进行远程对象(remote object)的通讯。stub 充当远程对象的客户端代理,有着和远程对象相同的远程接口,远程对象的调用实际是通过调用该对象的客户端代理对象stub来完成的。 每个远程对象都包含一个代理对象stub,当运行在本地Java虚拟机上的程序调用运行在远程Java虚拟机上的对象方法时,它首先在本地创建该对象的代理对象stub, 然后调用代理对象上匹配的方法。每一个远程对象同时也包含一个skeleton对象,skeleton运行在远程对象所在的虚拟机上,接受来自stub对象的调用。这种方式符合等到程序要运行时将目标文件动态链接的思想。
27、
28、 简单记忆线程安全的集合类: 喂! SHE ! 喂是指 vector , S 是指 stack , H 是指 hashtable , E 是指: Eenumeration
线程安全概念: 如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则的话就可能影响线程安全。
LinkedList 和 ArrayList 都是不同步的,线程不安全; Vector 和 Stack 都是同步的,线程安全; Set是线程不安全的;
Hashtable的方法是同步的,线程安全; HashMap的方法不是同步的,线程不安全;
29、 30、 A.StringBuilder线程不安全,StringBuffer线程安全。 B.同时用 abstract和final就会自相矛盾。 C.Hashmap中的value可以之null,get(key)==null有两种情况,一是key不存在,二是该key中存的是null,所以应该使用map.containskey(key)返回的true/false来判断是否存在这个key。 D.volatile关键字有两个作用: 1.并发环境可见性:volatile修饰后的变量能够保证该变量在线程间的可见性,线程进行数据的读写操作时将绕开工作内存(CPU缓存)而直接跟主内存进行数据交互,即线程进行读操作时直接从主内存中读取,写操作时直接将修改后端变量刷新到主内存中,这样就能保证其他线程访问到的数据是最新数据 2.并发环境有序性:通过对volatile变量采取内存屏障(Memory barrier)的方式来防止编译重排序和CPU指令重排序,具体方式是通过在操作volatile变量的指令前后加入内存屏障,来实现happens-before关系,保证在多线程环境下的数据交互不会出现紊乱。
31、 按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。
节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader. **处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。**如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。 JAVA常用的节点流:
文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流。 字符串 StringReader StringWriter 对字符串进行处理的节点流。 数 组 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。 管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter对管道进行处理的节点流。 常用处理流(关闭处理流使用关闭里面的节点流)
缓冲流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter 增加缓冲功能,避免频繁读写硬盘。 转换流:InputStreamReader OutputStreamReader 实现字节流和字符流之间的转换。 数据流 DataInputStream DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来. 流的关闭顺序 一般情况下是:先打开的后关闭,后打开的先关闭 另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b。例如,处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b 可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。
32、(?) get方法是获得user对象下前面指定好的属性的值,而获取static属性时get()括号里的对象可以写成null
33、 以java8为准,switch支持10种类型 基本类型:byte char short int 对于包装类 :Byte,Short,Character,Integer String enum 在Java7之前,switch只能支持 byte、short、char、int或者其对应的封装类以及Enum类型。在Java7中,也支持了String类型 String byte short int char Enum 类型
34、 A,“任何对象”锁定,太绝对了,你能锁住你没有权限访问的对象吗? B,前半句话讲的是创建线程的方式,后半句讲的是锁定,驴头不对马嘴。 C,正确。 D,线程调度分为协同式调度和抢占式调度,Java使用的是抢占式调度,也就是每个线程将由操作系统来分配执行时间,线程的切换不由线程本身来决定(协同式调度)。这就是平***立的原因。 以上,选CD 线程的互斥锁机制:synchronized,lock,condition
35、 主要考核了这几个知识点: 1.静态内部类才可以声明静态方法 2.静态方法不可以使用非静态变量 3.抽象方法不可以有函数体
这是我学习Java内部类的笔记 1.为什么使用内部类? 使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现, 对于内部类都没有影响 1.1.使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,使用内部类还能够为我们带来如下特性: (1)、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独。 (2)、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。 (3)、创建内部类对象的时刻并不依赖于外围类对象的创建。 (4)、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。 (5)、内部类提供了更好的封装,除了该外围类,其他类都不能访问。 2.内部类分类: (一).成员内部类:
public class Outer{ private int age = 99; String name = “Coco”; public class Inner{ String name = “Jayden”; public void show(){ System.out.println(Outer.this.name); System.out.println(name); System.out.println(age); } } public Inner getInnerClass(){ return new Inner(); } public static void main(String[] args){ Outer o = new Outer(); Inner in = o.new Inner(); in.show(); } } 1.Inner 类定义在 Outer 类的内部,相当于 Outer 类的一个成员变量的位置,Inner 类可以使用任意访问控制符, 如 public 、 protected 、 private 等 2.Inner 类中定义的 show() 方法可以直接访问 Outer 类中的数据,而不受访问控制符的影响, 如直接访问 Outer 类中的私有属性age 3.定义了成员内部类后,必须使用外部类对象来创建内部类对象,而不能直接去 new 一个内部类对象, 即:内部类 对象名 = 外部类对象.new 内部类( ); 4.编译上面的程序后,会发现产生了两个 .class 文件: Outer.class,Outer$Inner.class{} 5.成员内部类中不能存在任何 static 的变量和方法,可以定义常量: (1).因为非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关, 简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不通过; 非静态内部类的作用域是实例级别 (2).常量是在编译器就确定的,放到所谓的常量池了 ★★友情提示: 1.外部类是不能直接使用内部类的成员和方法的,可先创建内部类的对象,然后通过内部类的对象来访问其成员变量和方法; 2.如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量, 可以使用 this 关键字,如:Outer.this.name (二).静态内部类: 是 static 修饰的内部类, 1.静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 2.如果外部类的静态成员与内部类的成员名称相同,可通过“类名.静态成员”访问外部类的静态成员; 如果外部类的静态成员与内部类的成员名称不相同,则可通过“成员名”直接调用外部类的静态成员 3.创建静态内部类的对象时,不需要外部类的对象,可以直接创建 内部类 对象名 = new 内部类();
public class Outer{ private int age = 99; static String name = “Coco”; public static class Inner{ String name = “Jayden”; public void show(){ System.out.println(Outer.name); System.out.println(name); } } public static void main(String[] args){ Inner i = new Inner(); i.show(); } } (三).方法内部类:其作用域仅限于方法内,方法外部无法访问该内部类 (1).局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的 (2).只能访问方法中定义的 final 类型的局部变量,因为: 当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在, 直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量; ==>使用final修饰符不仅会保持对象的引用不会改变,而且编译器还会持续维护这个对象在回调方法中的生命周期. 局部内部类并不是直接调用方法传进来的参数,而是内部类将传进来的参数通过自己的构造器备份到了自己的内部, 自己内部的方法调用的实际是自己的属性而不是外部类方法的参数; 防止被篡改数据,而导致内部类得到的值不一致
/* 使用的形参为何要为 final??? 在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的, 也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的, 毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解 和不可接受的,所以为了保持参数的一致性,就规定使用 final 来避免形参的不改变 */ public class Outer{ public void Show(){ final int a = 25; int b = 13; class Inner{ int c = 2; public void print(){ System.out.println(“访问外部类:” + a); System.out.println(“访问内部类:” + c); } } Inner i = new Inner(); i.print(); } public static void main(String[] args){ Outer o = new Outer(); o.show(); } } (3).注意:在JDK8版本之中,方法内部类中调用方法中的局部变量,可以不需要修饰为 final,匿名内部类也是一样的,主要是JDK8之后增加了 Effectively final 功能 http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html 反编译jdk8编译之后的class文件,发现内部类引用外部的局部变量都是 final 修饰的 (四).匿名内部类: (1).匿名内部类是直接使用 new 来生成一个对象的引用; (2).对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,创建匿名内部类时它会立即创建一个该类的实例, 该类的定义会立即消失,所以匿名内部类是不能够被重复使用; (3).使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口; (4).匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法; (5).匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法 (6).匿名内部类初始化:使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果
public class OuterClass { public InnerClass getInnerClass(final int num,String str2){ return new InnerClass(){ int number = num + 3; public int getNumber(){ return number; } }; /* 注意:分号不能省 */ } public static void main(String[] args) { OuterClass out = new OuterClass(); InnerClass inner = out.getInnerClass(2, “chenssy”); System.out.println(inner.getNumber()); } } interface InnerClass { int getNumber(); }
|