1.jdk和jre有什么区别?
JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境。JRE:Java Runtime Environment 的简称,java 运行环境,为 java 的运行提供了所需环境。 具体来说 JDK 其实包含了 JRE,同时还包含了编译 java 源码的编译器 javac,还包含了很多 java 程序调试和分析的工具。简单来说:如果你需要运行 java 程序,只需安装 JRE 就可以了,如果你需要编写 java 程序,需要安装 JDK。2. JDK安装目录下主要文件夹及文件功能: (1)bin文件夹:提供JDK工具程序,包括javac、java、javadoc、appletviewer等可执行程序。 (2)demo文件夹:Sun公司为Java使用者提供给的一些已经编写好的范例程序。 (3)jre文件夹:存放Java运行环境文件。 (4)lib文件夹:存放Java的类库文件,即工具程序使用的Java类库。JDK中的工具程序大多也是由Java编写而成。 (5)include文件夹:存放用于本地方法的文件。
3.JDk 的bin文件夹有很多exe文件: javac:Java编译器,将Java源代码换成字节代 java:Java解释器,直接从类文件执行Java应用程序代码 appletviewer:(小程序浏览器):一种执行HTML文件上的Java小程序类的Java浏览器 javadoc:根据Java源代码及其说明语句生成的HTML文档 jdb:Java调试器,可以逐行地执行程序、设置断点和检查变量 javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件
4.JDK、JRE、JVM三者间的关系 JDK中包含JRE,在JDK的安装目录下有一个名为jre的目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。
5.java程序运行机制: Java首先编写的Java源程序(.java),再利用编译器(javac)将源程序编译为字节码文件(.class);最后利用虚拟机解释运行。 6.jdk各版本的区别: 点击 参考别的博客
jdk1.5新特性 1.自动装箱与拆箱:原始类型与对应的包装类不用显式转换 ArrayList list=new ArrayList()----------->ArrayList<Integer>list=new ArrayList<Integer>(); 2.静态导入:通过使用 import static,就可以不用指定 Constants 类名而直接使用静态成员,包括静态方法。 Math.sqrt();----------->sqrt(); 3.For-Each循环:For-Each循环得加入简化了集合的遍历。 for(i=0;i<a.length;i++){......}----------->for(int i:a){......} 4.泛型:可以指定集合的元素类型。 ArrayList list=new ArrayList()----------->ArrayList<Integer>list=new ArrayList<Integer>(); 5.变长参数:有任意个参数,看作数组。 int sum(int ...intlist) jdk1.6新特性 1.使用Compiler API 在早期的版本中(Java SE5及以前版本)中只能通过tools.jar中的com.sun.tools.javac包来调用Java编译器,但由 于tools.jar不是标准的Java库,在使用时必须要设置这个jar的路径。 在1.6之后jdk提供了一套compiler API,定义在JSR199中,提供在运行期动态编译java代码为字节码的功能 2.轻量级Http Server API HttpServer 是 JDK 1.6 以后内置的一个轻量级 HTTP 服务器(在 rt.jar 包中的 com.sun.net.httpserver 包下)。 一个 HttpServer 实例被绑定到一个IP地址和端口号,并监听来自该地址的客户端TCP连接。其子类HttpsServer 实现了 HTTPS 服务,还能处理 HTTPS 请求。 jdk1.7新特性 1.switch中可以使用字符串 2.对集合类的语言支持:Java将包含对创建集合类的第一类语言支持。这意味着集合类的创建可以像Ruby和Perl那样了(下面的这些集合是不可变的)。 原本需要这样: List<String> list = new ArrayList<String>(); list.add("item"); String item = list.get(0); Set<String> set = new HashSet<String>(); set.add("item"); Map<String, Integer> map = new HashMap<String, Integer>(); map.put("key", 1); int value = map.get("key"); 现在你可以这样: List<String> list = ["item"]; String item = list[0]; Set<String> set = {"item"}; Map<String, Integer> map = {"key" : 1}; int value = map["key"]; jdk1.8新特性 1.HashMap中的红黑树:HashMap中链长度大于8时采取红黑树的结构存储。 红黑树,除了添加的情况外,其他时候效率高于链表结构。(多了红黑树) 2.ConcurrentHashMap:底层采用node数组+链表+红黑树的存储结构,通过CAS算法(乐观锁机制)+synchronized来保证并发安全的实现。 put()方法过程: 1) 根据key的hash值数组中相应位置的Node还未初始化,则通过CAS插入相应的数据; 2) 如果相应位置的Node不为空,且当前该节点不处于移动状态,则对该节点加synchronized锁,如果该节点的 hash不小于0,则遍历链表更新节点或插入新节点; 3) 如果该节点是TreeBin类型的节点,说明是红黑树结构,则通过putTreeVal方法往红黑树中插入节点; 3.接口中可以有默认方法与静态方法,也就是接口中可以有实现方法 默认方法中的default不可省略,子类重写时候,必须去掉default修饰符 4.Lambda表达式:lambda表达式的使用简化了代码。 jdk1.9新特性 1.在1.8的基础上又增加了私有方法和私有静态方法(1.8首次计划实现接口的私有方法,却是在1.9中实现)。 2.模块化系统:模块化是一个很通用的概念。在软件中,模块化可以运用到编写和实现一个程序和计算系统, 他们都是作为独立的模块,而不是作为一个单一的和完整的设计。 3.JShell–Java 9 REPL:REPL是一种快速运行语句的命令行工具。 4.集合工厂方法:1.9引入了一些有用的工厂方法来创建不可修改的集合。 5.G1是Java 9中的默认GC对jdk1.8 新增接口可以有实现方法,default解释
7.Java的平台无关性如何体现出来的: Java程序则编译为字节码。字节码本身不能运行,因为它不是原生代码。字节码只能够在Java虚拟机(JVM)上运行。JVM是一个原生应用程序,它负责解释字节码。通过使用JVM可用在众多的平台上(这也就是Java可以做到平台无关性的原因),Sun公司将Java变成了跨平台的语言。如下图模型,完全相同的字节码可以在已经开发了JVM的任何操作系统上运行。 8.强软弱虚引用 为啥要引入: 因为java不用手动管理内存,但正是因为如此,JVM才要更加高效的管理申请的内存。如果做到更加高效呢?
对强软弱虚引用的理解 强软弱虚对应着四种内存情况,我们以申请内存时的引用类型,来告诉JVM,当前内存的优先级。 举个栗子,JVM就是债主,强软弱虚分别代表了四种不同性格的借款人。 Mr.强引用:我丫就是借了,甭管你朝我要几次(发生GC),我都不会还给你的,除非我攒齐了(内存不再使用,不再被GC ROOT集合中的对象引用)。 Mr.软引用:我借了你的钱,所以欠你人情,所以这样吧,当你实在没办法回笼资金的时候(内存不够用),我就把钱还给你,如果你够用,我就先不还你了。 Mr.弱引用:我借了你的钱,所以我欠你的,只要你朝我要钱(发生GC),我就还给你吧。 Mr.虚引用:我就是来凑数的,我不缺钱(不影响GC回收内存),就是想体验一把还钱的滋味(接收内存回收时的通知)。 理解连接1 理解链接2
9.Hashcode的作用: 以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样: 1.new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去,串在一起。 2.比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal.
10.== 和 equals 的区别是什么?
对于基本类型和引用类型 == 的作用效果是不同的,如下所示: 基本类型:比较的是值是否相同; 引用类型:比较的是引用是否相同;
String x = "string"; String y = "string"; String z = new String("string"); System.out.println(x==y); // true System.out.println(x==z); // false System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。 equals 解读: equals 本质上就是 ==,只不过 String 和 Integer 等重写了 equals 方法,把它变成了值比较。看下面的代码就明白了。首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:
class Cat { public Cat(String name) { this.name = name; } private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } Cat c1 = new Cat("王磊"); Cat c2 = new Cat("王磊"); System.out.println(c1.equals(c2)); // false输出结果出乎我们的意料,竟然是 false?这是怎么回事,看了 equals 源码就知道了,源码如下:
public boolean equals(Object obj) { return (this == obj); } //自己写的对象类,没有重写object的equals,所以默认使用的object,本质是==,比较的引用是否相同那问题来了,两个相同值的 String 对象,为什么返回的是 true?代码如下:
String s1 = new String("老王"); String s2 = new String("老王"); System.out.println(s1.equals(s2)); // true同样的,当我们进入 String 的 equals 方法,找到了答案,代码如下:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }原来是 String 重写了 Object 的 equals 方法,把引用比较改成了值比较。
总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重写了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
11.final 在 java 中有什么作用?
final 修饰的类叫最终类,该类不能被继承。final 修饰的方法不能被重写。final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。12.String 属于基础的数据类型吗? String 不属于基础类型,基础类型有 8 种:byte、boolean、char、short、int、float、long、double,而 String 属于对象。
13.java 中操作字符串都有哪些类?它们之间有什么区别? 操作字符串的类有:String、StringBuffer、StringBuilder。 String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。 StringBuffer就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类 StringBuffer和StringBuilder有公共父类AbstractStringBuilder(抽象类)。
StringBuffer、StringBuilder的方法都会调用AbstractStringBuilder中的公共方法,如上面的两段源码中都调用了super.append(str); 只是StringBuffer会在方法上加synchronized关键字,进行同步。 string stringBuffer stringBuilder拓展
14.StringBuffer和数组的区别?
二者都可以看做是以个容器,装其他数据的容器。但是,StringBuffer的数据最终是一个字符串数据而数组可以放置多种数据,但必须是用同一种数据类型的15.String str="i"与 String str=new String(“i”)一样吗? 不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。
16.如何将字符串反转? 使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。 reverse源代码:
public AbstractStringBuilder reverse() { boolean flag = false; int i = count - 1; for(int j = i - 1 >> 1; j >= 0; j--) { char c = value[j]; char c2 = value[i - j]; if(!flag) //确定给定char值是否为一个Unicode高/低代理项代码单元 flag = c >= '\uD800' && c <= '\uDFFF' || c2 >= '\uD800' && c2 <= '\uDFFF'; value[j] = c2; value[i - j] = c; } if(flag) { for(int k = 0; k < count - 1; k++) { char c1 = value[k]; if(!Character.isLowSurrogate(c1)) continue; char c3 = value[k + 1]; if(Character.isHighSurrogate(c3)) { value[k++] = c3; value[k] = c1; } } } return this; }17.StringBuffer如何实现修改append?(推荐看源代码) append 方法主要的工作是:获得要追加的字符串的长度,判断当前字符数组是否能够存储追加的字符串,如果容量不够则确定新的字符数组的容量,申请新的字符数组,将以前字符数组的内容复制到新字符数组。最后将要追加的字符串,复制到新字符数组中。链接描述
18.String 类的常用方法都有那些?
indexOf():返回指定字符的索引。charAt():返回指定索引处的字符。replace():字符串替换。trim():去除字符串两端空白。split():分割字符串,返回一个分割后的字符串数组。getBytes():返回字符串的 byte 类型数组。length():返回字符串长度。toLowerCase():将字符串转成小写字母。toUpperCase():将字符串转成大写字符。substring():截取字符串。equals():字符串比较。19.String不可变性 至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以 Java 标准类库还提供了一个可变版本,即 StringBuffer。
Javac 编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。所以 String s=“a”+”b”+”c”+”d”;只生成一个对象.
20.不可变对象 如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变。
21.如何创建不可变类
将类声明为final,所以它不能被继承将所有的成员声明为私有的,这样就不允许直接访问这些成员对变量不要提供setter方法将所有可变的成员声明为final,这样只能对它们赋值一次通过构造器初始化所有成员,进行深拷贝(deep copy):如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。在getter方法中,不要直接返回对象本身,而是克隆对象,并返回对象的拷贝22.为什么String要设计成不可变的 在Java中将String设计成不可变的是综合考虑到各种因素的结果,如内存,同步,数据结构以及安全等方面的考虑.
字符串常量池的需要. 字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。
线程安全考虑。 同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。
支持hash映射和缓存。 因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串。
23.抽象类必须要有抽象方法吗? 不需要,抽象类不一定非要有抽象方法。
24.普通类和抽象类有哪些区别?
普通类不能包含抽象方法,抽象类可以包含抽象方法。抽象类不能直接实例化,普通类可以直接实例化。25.抽象类能使用 final 修饰吗? 不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类,
26.接口和抽象类有什么区别?
实现:抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口。构造函数:抽象类可以有构造函数;接口不能有。main 方法:抽象类可以有 main 方法,并且我们能运行它;接口不能有 main 方法。实现数量:类可以实现很多个接口;但是只能继承一个抽象类。访问修饰符:接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符。27.BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。NIO:New IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。拓展链接28.Files的常用方法都有哪些?
Files.exists():检测文件路径是否存在。Files.createFile():创建文件。Files.createDirectory():创建文件夹。Files.delete():删除一个文件或目录。Files.copy():复制文件。Files.move():移动文件。Files.size():查看文件个数。Files.read():读取文件。Files.write():写入文件。29.什么是 Java 序列化,如何实现 Java 序列化 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。
序列化的实现:将需要被序列化的类实现 Serializable 接口,该接口没有需要实现的方法, implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
30.静态变量和实例变量的区别 在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
31.是否可以在 static 环境中访问非 static 变量 static 变量在 Java 中是属于类的,它在所有的实例中的值是一样的。当类被Java虚拟机载入的时候,会对 static 变量进行初始化。如果你的代码尝试不用实例来访问非 static 的变量,编译器会报错,因为这些变量还没有被创建出来,还没有跟任何实例关联上。
32.什么是 Java 序列化,如何实现 Java 序列化 参考文章
33.int和Integer的区别 参考文章 不是说我懒,不去整理不去写,之接粘贴个别人的链接,而是别人写的真的很好了,没有必要再去照搬过来。
34.float f=3.4;是否正确? 错,3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。
35.在Java中,如何跳出当前的多重嵌套循环? break语句2种,(break是结束整个循环体,continue是结束单次循环(跳出当前循环,到下一步))详情见博客 return
36.构造器(constructor)是否可被重写(override)? Constructor(构造器)不能被继承,所以不能被override(重写),但是可以被overloading(重载)
37.当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?(很有争议的话题) 是值传递。Java编程语言中只有由值传递参数的。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。 总结:“Java总是值传递的”。我们所以为的按引用传递,其实传递的还是引用中地址的值(并且是它的一个拷贝),也可以理解为指针的值。让我们所疑惑的,只是“引用”这个词的含义,在Java中的引用和我们广以为的引用是有所不同的。
38.重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法。39.char 型变量中能不能存贮一个中文汉字,为什么? 可以,char类型是用来存储unicode编码的,汉字包含在了unicode编码中,所以char可以存储汉字,如果unicode编码不包含某个特殊的汉字那就不能存储这个汉字了,unicode编码占2字节,所以char类型的变量占2个字节
40.Java 中会存在内存泄漏吗,请简单描述。 内存泄露的发生场景,通俗地说,就是程序员可能创建了一个对象,以后一直不再使用这个对象,这个对象却一直被引用,即这个对象无用但是却无法被垃圾回收器回收的,这就是java中的内存泄露,一定要让程序将各种分支情况都完整执行到程序结束,然后看某个对象是否被使用过,如果没有,则才能判定这个对象属于内存泄露
如果一个外部类的实例对象的方法返回了一个内部类的实例对象,这个内部类对象被长期引用了,即使那个外部类实例对象不再被使用,但由于内部类持久外部类的实例对象,这个外部类对象将不会被垃圾回收,这也会造成内存泄露。当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,造成内存泄露。41.抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰? 抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。 本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。
synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的
42.阐述静态变量和实例变量的区别。 静态(static)变量不需要实例化,类被加载后即可调用,实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
43.如何实现对象克隆?
实现对象克隆有两种方式:深入理解 1). 实现Cloneable接口并重写Object类中的clone()方法; 2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。**注意:**基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。44.String s = new String(“xyz”);创建了几个字符串对象? 两个,一个string s new出来的对象,一个“xyz”常量池对象
45.接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?
接口可以继承接口,而且支持多重继承。抽象类可以实现(implements)接口。抽象类可继承具体类也可以继承抽象类。46.一个".java"源文件中是否可以包含多个类(不是内部类)?有什么限制? 可以 ,但有且仅有一个public类,类名与xxx.java的xxx相同
47.Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口? 匿名内部类在实现时必须借助一个借口或者一个抽象类或者一个普通类来构造,从这过层次上讲匿名内部类是实现了接口或者继承了类,但是不能通过extends或implement关键词来继承类或实现接口。
匿名内部类即没有名字的内部类。当我们只需要用某一个类一次时,且该类从意义上需要实现某个类或某个接口,这个特殊的扩展类就以匿名内部类来展现。
一般的用途: 1、覆盖某个超类的方法,并且该扩展类只在本类内用一次。 2、继承抽象类,并实例化其抽象方法,并且该扩展类只在本类内用一次。 3、实现接口,实例化其方法,并且该扩展类只在本类内用一次。
注意: 一、由于匿名内部类没有名字,所以它没有构造函数。因为没有构造函数,所以它必须完全借用父类的构造函数来实例化,匿名内部类完全把创建对象的任务交给了父类去完成。 二、在匿名内部类里创建新的方法没有太大意义,但它可以通过覆盖父类的方法达到神奇效果,如上例所示。这是多态性的体现。 三、因为匿名内部类没有名字,所以无法进行向下的强制类型转换,持有对一个匿名内部类对象引用的变量类型一定是它的直接或间接父类类型。 四、注意匿名内部类的声明是在编译时进行的,实例化在运行时进行。这意味着for循环中的一个new语句会创建相同匿名类的几个实例,而不是创建几个不同匿名类的一个实例。
48.内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 完全可以。如果不是静态内部类,那没有什么限制! 一个内部类对象可以访问创建它的外部类对象的成员包括私有成员。 如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员。
49.3*0.1==0.3返回值是什么 false,因为有些浮点数不能完全精确的表示出来。链接描述
原文链接:https://blog.csdn.net/weixin_42398872/article/details/102785533