1. 面向对象三大特性
面向对象三个基本特征:封装、继承、多态;
Java语言以对象为中心,最小单位为类。
封装:封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口;
继承:继承是从已有类获得继承信息建立新类的过程;
多态:多态是指容许不一样子类型的对象对同一消息做出不一样的响应。
2. 建立对象的方式
(1)使用new语句建立对象 这是最多见的方式
(2)使用反射手段,调用java.lang.Class或java.lang.reflect.Constructor类的newInstance()方法
(3)调用对象的clone方法 须要实现Cloneable接口
(4)运用反序列化手段 调用java.io.ObjectInputStream对象的readObject方法
(5)建立子类对象时,若是父类对象未被建立......
其中1,2,5都会调用构造函数,3是在内存上对已有对象的影印 因此不会调用构造函数,4是从文件中还原类的对象 也不会调用构造函数;
Class.newInstance只能调用无参的构造函数;Constructor.newInstance能够调用有参和私有的构造函数;
Employee emp = (Employee) Class.forName("com.test.Employee").newInstance();
or
Employee emp = Employee.class.newInstance();
Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp2 = constructor.newInstance();
不管什么时候调用一个对象的clone方法,JVM都会建立一个新的对象,将前面对象的内容所有拷贝进去;用clone方法建立对象并不会调用任何构造函数;要使用clone方法,咱们须要先实现Cloneable接口并实现其定义的clone方法
Employee emp3 = (Employee) emp2.clone();
为了反序列化一个对象,咱们须要让类实现Serializable接口;
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp4 = (Employee) in.readObject();
3. 什么是对象的序列化与反序列化,用在什么地方,如何使用
Java中的序列化指的是将对象转换成以字节序列的形式来表示,这些字节序列包含了对象的数据信息,一个序列化后的对象能够被写到数据库或文件中,也可用于网络传输。通常当咱们使用缓存cache(内存空间不够有可能会本地存储到硬盘)或远程调用RPC(网络传输)的时候,常常须要让咱们的实体类实现Serializable接口,目的就是让其可序列化(交互双方的一个公共标准);
序列化后的最终目的是为了反序列化,恢复成原先的Java对象,因此序列化后的字节序列都是能够恢复成Java对象的,这个过程就是反序列化;
一旦变量被transient修饰,变量将再也不是对象持久化的一部分,该变量内容在序列化后没法得到访问。也能够认为在将持久化的对象反序列化后,被transient修饰的变量将按照普通类成员变量同样被初始化;
一个静态变量无论是否被transient修饰,均不能被序列化,由于是类级别的;
最后,为何要不被序列化呢,主要是为了节省存储空间。
4. JVM的实现原理、内存模型
Java语言既是编译型语言,又是解释型语言:Java源码经过javac命令被编译成.class文件,这种字节码文件不面向任何平台,只面向JVM(Java Virtual Machine);JVM是Java跨平台的关键部分,其向上提供给Java字节码程序的接口彻底相同,而向下适应不一样平台的接口则互不相同,为特定平台提供特定机器码,使用java命令解释执行;
程序计数器、虚拟机栈、本地方法栈3个区域随线程而生,随线程而灭,所以这几个区域的内存分配和回收都具有肯定性,就不须要过多考虑回收的问题,由于方法结束或者线程结束时,内存天然就跟随着回收了;而Java堆区和方法区的分配和回收是动态的,是GC须要关注的部分。
5. GC原理
要请求垃圾收集,能够将相关对象设置为null或调用System.gc() ,但后者将会严重影响代码性能,由于通常每一次显式调用System.gc()都会中止全部的响应,去检查内存中是否有可回收的对象,这样会对程序的正常运行形成极大的威胁。另外,调用该方法并不能保证JVM当即进行垃圾回收,仅仅是通知JVM要进行垃圾回收了,具体回收与否彻底由JVM决定,这样作是费力不讨好;
垃圾回收器一般是做为一个单独的低优先级的守护线程运行,不可预知的状况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收;
有两种算法能够断定对象是否存活:
(1)引用计数法,可是它很难解决两个对象之间相互循环引用的状况;
(2)可达性分析法,在主流的商用程序语言(如咱们的Java)的主流实现中,都是经过可达性分析算法来断定对象是否存活的;
堆分新生代与老年代,具体操做流程:
新生代:包含Eden与两个Survivor,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块Survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又被送入第二块Survivor space S1,S0和Eden被清空,而后下一轮S0与S1交换角色,如此循环往复。若是对象的复制次数达到16次,该对象就会被送到老年代中;
与垃圾回收相关的JVM参数:
-Xms / -Xmx — 堆的初始大小 / 堆的最大大小
-Xmn — 堆中新生代的大小(同时设置XX:NewSize=XX:MaxNewSize),实际可用空间 = Eden + 1个Survivor,即90%
-Xss — 每一个线程堆栈的大小,通常来讲若是栈不是很深的话,1M绝对够用了
-XX:NewSize / -XX:MaxNewSize — 设置新生代大小/新生代最大大小
-XX:NewRatio — 新生代与老年代的比例,2表明新生代占整个堆空间的1/3,老年代占2/3
常见垃圾回收方式:
标记清除法:这是垃圾收集算法中最基础的,分为标记和清除两个阶段,它的思想是标记哪些要被回收的对象,而后统一回收。这种方法很简单,可是效率不高,标记和清除的效率都很低。此外会产生大量不连续的内存碎片,从而致使之后程序在分配较大对象时因为没有充足的连续内存而提早触发一次 GC 操做;
复制算法:为了解决效率问题,复制算法将可用内存按容量划分为相等的两部分,而后每次只使用其中的一块,当一块内存用完后就将还存活的对象复制到第二块内存上,而后一次性清除完第一块内存,再将第二块上的对象复制到第一块。可是这种方式内存的代价过高,每次基本上都要浪费一半的内存;因而将该算法进行了改进,内存区域再也不是按照1: 1去划分,而是将内存划分为8: 1: 1三部分,较大那分内存是Eden区,其他是两块较小的内存区叫Survior区,每次都会优先使用Eden区,若Eden区满则将对象复制到第二块内存区上,而后清除Eden区,若是此时存活的对象太多,以致于Survivor不够时,会将这些对象经过分配担保机制复制到老年代中;
标记整理法:这种方法主要是为了解决标记清除法产生大量内存碎片的问题。当对象存活率较高时,也解决了复制算法的效率问题。它的不一样之处就是在清除对象的时候先将可回收对象移动到一端,而后清除掉端边界之外的对象,这样就不会产生内存碎片了,可是会增长停顿时间;
分代收集法:如今的虚拟机垃圾收集大多采用这种方式,它根据对象的生存周期,将堆分为新生代和老年代。在新生代中,因为对象生存期短,每次回收都会有大量对象死去,那么这时就采用复制算法,新生代又分为Eden和两个Survivor,大小比例默认8: 1: 1。老年代里的对象存活率较高,没有额外的空间进行分配担保,因此可使用标记整理法或标记清除法。
大对象直接进入老年代:JVM中有个参数配置-XX: PretenureSizeThreshold,令大于这个设置值的对象直接进入老年代,目的是为了不在Eden和Survivor区之间发生大量的内存复制。
Java对象使用后设置为null并不会减小内存占用,设置为null只是栈中指向的引用为null,可是new出来的对象仍是存在于堆里面的,须要等到GC算法调用时才能将没有栈指向的对象给回收掉。
6. Java中的集合类有哪些
Java集合大体可分为Set、List、Queue、Map四种体系;
Set:表明无序、不可重复;
List:表明有序、可重复;
Queue:表明一种队列集合的实现;
Map:表明具备映射关系的集合。
Java集合主要有两个接口派生而出:Collection和Map,Collection接口是Set、List、Queue接口的父接口;
Set与Collection基本相同,没有额外提供其它方法,实际上Set就是Collection,只是行为略有不一样,Set不容许包含重复元素,添加同一对象两次到集合中,第二次会操做失败,add返回false;
List集合容许使用重复元素,能够经过索引来访问指定位置的元素;
Map与Set的关系:若是把Map里全部key放在一块儿看,它们就组成了一个Set集合(全部的key没有顺序,key与key之间不重复),实际上Map确实包含了一个keySet方法,用户返回Map里全部key组成的Set集合;
Map与List的关系:若是把Map里全部value放在一块儿看,它们就组成了一个List,元素与元素之间能够重复,每一个元素能够根据索引来查找,只是Map中索引再也不使用整数值,而是以另一个对象做为索引。
7. LinkedList与ArrayList的区别
两者都容许null元素;
ArrayList的内部实现是基于内部动态数组Object[],因此从概念上讲,它更像数组,但LinkedList的内部实现是基于一组链接的记录,因此它更像一个链表结构。ArrayList更适合get和set,由于LinkedList本质是双向链表,须要从头移动指针进行查找,而ArrayList能够直接按序号索引元素;LinkedList更适合add和remove,由于ArrayList须要移动数据(直接在数组末尾add性能也很高,可是若是按照下标来插入、删除元素,就须要经过Arrays.copyof函数来移动部分受影响的元素,性能变差);
ArrayList在要增长数据时,都会调用ensureCapacity方法来确保有足够的容量。当容量不够时,就设置新的容量为旧容量的1.5倍(默认容量为10),若是还不够,就直接将容量设置为所需容量,以后用Arrays.copyof方法将元素拷贝到新数组。所以,当容量不够时,每次增长元素都须要将原来的元素拷贝到一个新数组中,很是耗时,所以建议在事先知道元素数量的状况下再使用ArrayList,不然使用LinkedList;
ArrayList的空间浪费主要体如今在list列表的结尾预留必定的容量空间,而LinkedList的空间花费则体如今它的每个元素都须要消耗至关的空间,就存储密度来讲,ArrayList是优于LinkedList的;
总之,当操做是在一列数据的后面添加数据而不是在前面或中间,而且须要随机地访问其中的元素时,使用ArrayList会提供比较好的性能,当操做是在一列数据的前面或中间添加或删除数据,而且按照顺序访问其中的元素时,就应该使用LinkedList了。
8. 对HashMap的理解
(1)HashMap的功能是经过key可以快速地找到value;
(2)HashMap是基于数组来实现哈希表的,数组就比如内存储空间,数组的index就比如内存的地址;
(3)HashMap的每一个记录就是一个Entry<K, V>对象,数组中存储的就是这些对象,其中包含了key、value、hash、next四种结构元素;
(4)HashMap的哈希函数(put操做):当key为空,经过putForNullKey方法把元素放到最开始位置(table[0]),不然根据传递的key值获得hashCode(int hash=key.hashCode();),而后用这个hashCode与数组长度进行运算,获得一个int值,就是Entry要存储在数组的位置(下标);
(5)HashMap解决冲突:使用链地址法,每一个Entry对象都有一个引用next来指向链表的下一个Entry(若是链表长度超过阈值8,就把链表转换成红黑树,链表长度低于6,就把红黑树转回链表);
(6)HashMap的装填因子:默认为0.75(用于判断是否须要扩展HashMap的容量,扩大为原来的两倍,HashMap的默认length是16);
(7)HashMap的get操做:当key为空,则直接去哈希表的第一个位置table[0]对应的链表上查找,不然根据key算出hash值(数组下标),以后获取对应的Entry,而后判断Entry里的key,hash值或者经过equals比较是否与要查找的相同,相同则返回value,不然遍历该链表,直到找到为止,不然返回null(在HashMap中,经过get方法返回null,多是HashMap中没有该键,也多是该键对应的值为null,所以不能用get方法判断HashMap中是否存在某个键,须要使用containsKey方法);
(8)HashMap是非线程安全的,多线程环境下能够采用concurrent并发包下的ConcurrentHashMap,或使用以下初始方式:Map m = Collections.synchronizedMap(new HashMap(...));
(9)HashMap实现了Serializable接口,所以支持序列化,实现了Cloneable接口,能被克隆。
9. hashCode与equals方法的关系
hashCode方法的存在是为了减小equals方法的调用次数,从而提升程序效率;
若是equals方法获得的结果为true,两个对象hashCode值一定相等;
若是equals方法获得的结果为false,两个对象hashCode值不必定不一样;
若是两个对象hashCode值不等,equals方法的结果一定为false;
若是两个对象hashCode值相等,equals方法获得的结果未知。
在重写equals方法时,必须重写hashCode方法。
10. HashMap与HashTable方法的区别
(1)两者的存储结构与解决冲突的方法都是相同的;
(2)HashTable在不指定容量的状况下默认为11,而HashMap为16;HashTable不要求底层数组的容量必定要为2的整数次幂,而HashMap则要求必定为2的整数次幂;
(3)HashTable中的key和value都不容许为null,而HashMap中key和value都容许为null(key只能有一个为null,value能够有多个为null);可是若是在HashTable中有相似put(null, null)的操做,编译一样能够经过,由于key和value都是Object类型,但运行时会抛出NullPointerException异常;
(4)HashTable扩容时,将容量变为原来的2倍+1,而HashMap扩容时,将容量变为原来的2倍;
(5)HashTable计算hash值,直接用key的hashCode(),而HashMap从新计算了key的hash值;HashTable在求hash值对应的位置索引时,用的取模运算,而HashMap在求位置索引时,则用与运算,且这里通常先用hash&0x7FFFFFFF后,再对length计算,目的是将负的hash值转换为正值;
(6)HashMap拿掉了HashTable的contains方法(比较的是value是不是equal的),由于此方法容易引发误解;两个类都包含containsKey和containsValue方法;
(7)HashTable是线程安全的,HashMap是线程非安全的。
11. 数组与链表的区别
数组的特色:
(1)在内存中,数组是一块连续的区域,经过数组下标进行访问,下标从0开始;
(2)数组须要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间;
(3)插入和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移;删除数据时,这个数据后面的数据都要向前移;
(4)随机读取效率高,由于数组是连续的,知道每个数据的内存地址,能够直接找到指定的数据;
(5)不利于扩展,数组定义的空间不够时须要从新定义新数组而后复制。
数组的优势:
(1)随机访问性强
(2)查找速度快
数组的缺点:
(1)插入和删除效率低,由于要移动其它的元素
(2)可能浪费内存
(3)内存空间要求高,必须有足够的连续内存空间
(4)数组大小固定,不能动态扩展
适用场景:
(1)频繁查询,对存储空间要求不大,不多增长和删除的状况。
链表的特色:
(1)在内存中能够存在在任何地方,不要求连续;
(2)每个数据都保存了下一个数据的内存地址,经过这个地址找到下一个数据;
(3)增长数据和删除数据很容易;
(4)查找数据时效率很低,由于不具备随机访问性,因此访问某个位置的数据都要从第一个数据开始;
(5)不指定大小,扩展方便,链表大小不用定义,数据随意增删。
链表的优势:
(1)插入删除速度快
(2)内存利用率高,不会浪费内存
(3)大小没有固定,扩展灵活
(4)不须要初始化容量
链表的缺点:
(1)不能随机查找,必须从第一个开始遍历,查找效率低
(2)由于含有大量的指针域,占用空间较大
适用场景:
(1)数据量较小,须要频繁增长,删除操做的场景。
12. 对类加载过程的理解
BootStrapClassLoader对应JRE/lib/rt.jar;
ExtClassLoader对应JRE/lib/ext/*.jar;
AppClassLoader对应Classpath指定的全部jar或目录(默认的类加载器);
双亲委托机制:
当一个类加载器接收到一个类加载任务时,不会当即展开加载,而是将加载任务委托给它的父类加载器去执行,每一层的类加载器都采用相同的方式,直到委托给最顶层的启动类加载器为止。若是父类加载器没法加载委托给它的类,便将类的加载任务退回给下一级类加载器去执行加载。
13. Java中如何使用JDBC建立一个事务并提交java
java.sql.Connection conn = null; java.sql.PreparedStatement stmt = null; try { conn = DriverManager.getConnection("jdbc:oracle:thin:@host:1521:SID", "username", "passwd"); // 将自动提交设置为false,若设置为true,则数据库会把每一次数据更新认定为一个事务并自动提交 conn.setAutoCommit(false); stmt = conn.createStatement(); // 将A帐户中的金额减小500 stmt.execute("update t_account set amount = amount - 500 where account_id = 'A'"); // 将B帐户中的金额增长500 stmt.execute("update t_account set amount = amount + 500 where account_id = 'B'"); // 提交事务 conn.commit(); } catch (Exception e){ conn.rollback(); } finally { stmt.close(); conn.close(); }
14. Java如何实现多继承
使用内部类能够实现多继承,直接上代码:程序员
public class Test { private class MyCall extends Call { } private class MySendMessage extends SendMessage { } private MyCall call = new MyCall(); private MySendMessage sm = new MySendMessage(); public void call(String phoneNumber) { call.call(phoneNumber); } public void send(String phoneNumber) { sm.send(phoneNumber); } public static void main(String[] args) { Test t = new Test(); t.call("110"); t.send("119"); } } class Call { public void call(String phoneNumber) { System.out.println("call the number: " + phoneNumber); } } class SendMessage { public void send(String phoneNumber) { System.out.println("send the number: " + phoneNumber); } }
15. String、StringBuilder、StringBuffer比较
三个类的主要区别在于运行速度与线程安全;
运行速度:StringBuilder > StringBuffer > String
缘由:StringBuilder和StringBuffer是变量,String是常量;若String str = "abc"; str += "de";,str被初始化为abc,以后jvm建立一个新对象"abcde",将这个新对象赋值给str,而原来的"abc"会被垃圾回收机制回收,因此String对象的操做其实是一个不断建立新对象而且将旧对象回收的过程;而对StringBuilder和StringBuffer的操做是直接对变量进行更改,不包含对象的建立与回收操做;
String str = "abc" + "de"; //这个操做做用和String str = "abcde";相同,因此会很快,
String str1 = "abc", str2 = "de"; str1 = str1 + str2; //这个操做会很慢;
线程安全:StringBuilder是线程不安全的,StringBuffer是线程安全的;
String:适用于少许的字符串操做的状况;
StringBuilder:适用于单线程下在字符缓冲区进行大量操做的状况;
StringBuffer:适用多线程下在字符缓冲区进行大量操做的状况。
16. String与Integer的转换
Integer转换为String:
Integer i = 1;
System.out.println(i.toString());
System.out.println(Integer.toString(i));
System.out.println(String.valueOf(i));
String转换为Integer:
String str = "...";
Integer i = null;
if (str != null) {
i = Integer.valueOf(str);
}
(也可使用构造方法)
17. Java中去除字符串空格用什么函数
trim:去掉首尾的空格;
replace:去掉全部的空格,包括首尾、中间;将oldchar替换为newchar;
str = str.replace(" ", ""); //去掉全部空格;
replaceAll:去掉全部的空格;参数为regex(正则表达式);
str = str.replaceAll("\\s*", ""); //替换大部分空白字符,不限于空格;
str = str.replaceAll(" +", ""); //去掉全部空格;
\s能够匹配空格、制表符、换页符等空白字符的其中任意一个。
18. 自动装箱与拆箱的原理
自动装箱:当给一个Integer对象赋int值时,会调用Integer.valueOf方法,若是数值在-128~127之间,就会被缓存在内存中;若是不在这个范围内,就去new一个Integer对象。
自动拆箱:做用在包装类型上的二元运算符会致使拆箱操做,拆箱的实质是调用intValue方法;而==与!=二元运算符比较特殊,一个包装类型和一个基本类型或表达式(即包含算数运算)进行==或!=比较,会首先对包装类型进行拆箱操做,以后再比较;而对两个包装类型进行==或!=操做,会直接比较对象地址。
19. 值传递与引用传递的原理
值传递:函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法的操做都是对形参的修改,不影响实际参数的值;
引用传递:函数接收的是原始值的内存地址,在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操做将会影响到实际对象;
public void swap(Student x, Student y) {
Student temp = x;
x = y;
y = temp;
}
swap方法执行过程:
(1)将对象a、b的拷贝分别赋给x、y,此时a和x指向同一对象,b和y指向同一对象;
(2)swap方法完成x、y的交换,a、b并无变化;
(3)方法执行完毕,x、y再也不使用,a、b依旧指向以前的对象;
综上,Java的参数传递方式为:值传递。
20. 方法覆盖与方法重载的比较
方法重载:发生在编译时,被称为编译时多态,编译器能够根据参数类型选择使用哪一个方法;
方法覆盖(重写):发生在运行时,被称为运行时多态,由于在编译期编译器不知道也无法知道去调用哪一个方法,JVM会在代码运行时作出决定;
方法的重写要遵循“两同两小一大”规则,“两同”即方法名相同、形参列表相同;“两小”即子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出异常类应该比父类方法声明抛出的异常类更小或相等;“一大”指的是子类方法的访问权限应比父类方法的权限更大或相等;尤为须要指出的是,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法;
方法重载只与“两同一不一样”有关:同类名,同方法名,不一样参数列表。
21. 接口与抽象类的比较
(1)接口是公开的,public static final的Field,public abstract的method;抽象类能够有私有方法和私有变量,能够有构造器;
(2)接口是has-a关系;抽象类是is-a关系;
(3)一个类只能继承一次,可是能够实现多个接口;
(4)通常的应用,最顶层是接口,以后是抽象类,而后是实现类;
(5)举例:Door具备open和close功能,若是如今想添加一个报警功能alarm,最好的方案是设计一个抽象类Door,包含open和close方法;再设计一个接口包含alarm方法;由于Door都具备open和close方法而不必定具备alarm功能,具备alarm功能的不必定是Door,open与alarm本质上不是同一个层面上的东西;open和close对于Door来讲是is-a关系,alarm对于Door来讲是has-a关系。
22. 泛型的做用
Java1.5引入了泛型,全部的集合接口都在使用它。做用:
(1)泛型容许咱们为集合提供一个能够容纳的对象类型,所以,若是你添加其它类型的任何元素,它会在编译时报错;这避免了在运行时出现ClassCastException,由于你将在编译时获得报错信息;
(2)泛型也使得代码整洁,咱们不须要使用显式转换和instanceof操做符。
23. 什么是迭代器(Iterator)
迭代器是一种设计模式,它是一个对象,能够遍历并选择序列中的对象,而开发人员不须要了解该序列的底层结构;
java.lang.Iterable接口,被Collection继承;
iterator方法在set和list接口中都有定义,可是ListIterator仅存在于list接口中(或实现类中);
ListIterator有add方法,能够向List中添加对象,而Iterator不能;
ListIterator和Iterator都有hasNext和next方法,能够实现顺序向后遍历,可是ListIterator有hasPrevious和previous方法,能够实现逆向(顺序向前)遍历,Iterator就不能够;
ListIterator能够定位当前的索引位置,nextIndex和previousIndex能够实现,Iterator没有此功能;
均可实现删除对象,可是ListIterator能够实现对象的修改,set方法能够实现,Iierator仅能遍历,不能修改。
24. Error与Exception的比较
Java将全部的错误封装成一个对象,其根本父类为Throwable,Throwable有两个子类Error和Exception;
Error是Throwable的子类,用于指示合理的应用程序(JVM)不该该试图捕获的严重问题;
Exception类及其子类是Throwable的一种表现形式,它指出了合理的应用程序(JVM)想要捕获的条件;
RuntimeException是可能在Java虚拟机正常运行期间抛出的异常的超类,无需在throws中进行说明。RuntimeException也被称为未检查异常(unchecked Exception)(其他的Exception为已检查异常),未检查异常是由于程序员没有进行必要的检查,由于疏忽和错误而引发的异常;
已检查异常:定义方法时必须声明全部可能会抛出的已检查异常;在调用这个方法时,必须对其进行捕获,不然就将其传递下去。
25. 成员变量与局部变量的比较
成员变量:方法外部,类的内部定义的变量,成员变量存储在堆中的对象里面,由垃圾回收器负责回收;
局部变量:方法或语句块内部定义的变量,形式参数是局部变量,局部变量的数据存放于栈内存中。栈内存中的局部变量随着方法的消失而消失,不能使用访问控制符。
成员变量无需显式初始化;局部变量分为形参、方法局部变量、代码块局部变量,除了形参以外,局部变量都必须显式初始化。
在同一个类里,成员变量的做用范围是整个类内有效,一个类里不能定义两个同名的成员变量,即便一个是类Field,一个是实例Field也不行;
一个方法里不能定义两个同名的局部变量,即便一个是方法局部变量,一个是代码块局部变量或形参也不行;
Java容许局部变量和成员变量同名,若是方法里的局部变量和成员变量同名,局部变量会覆盖成员变量,若是须要在这个方法里引用被覆盖的成员变量,则可使用this(对于实例Field)或类名(对于类Field)做为调用者来限定访问成员变量。正则表达式