1.static
static 关键字不能应用于局部变量,因此它只能作用于域。
非 static 字段和方法必须与某个对象关联,然后通过对象访问。
static 字段和方法不必与某个对象相关联,可以通过对象访问,也可以在没有创建对象的情况下直接通过类名访问。
不能在 static 域中访问非 static 域的方法。
某类中含有 static 字段 i,那么该类的不同对象中的字段 i 都指向同一个存储空间,在一个对象对 i 进行操作都会影响其他对象中的 i 。一个 static 字段对每个类来说都只有一个存储空间,而非 static 字段则是对每个对象都有一个存储空间。
static 方法可以创建或使用与其类型相同的被命名对象。
构造器虽然没有显式地使用static关键字,但也是静态方法。
静态初始化动作只执行一次,静态代码块也只执行一次
2.throw 与 throws
throw 用于在方法中抛出一个异常对象。
throws 用于方法声明,多个异常用逗号隔开,表示该方法执行时可能发生这些异常。
如果方法中使用 throw 抛出异常,那么必须对方法进行异常声明。
当方法使用 throws 进行异常声明后,调用方法时必须对其进行异常捕获。
当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常。
异常限制对构造器不起作用,子类构造器可以抛出任何异常,但是子类构造器的异常说明中必须包含基类构造器的异常说明。
子类方法可以不抛出任何异常,即使是基类所定义的异常。
⚪若接口中方法含有异常声明,实现类中的方法可以不含有异常声明;但如果接口中方法没有异常声明,实现类中方法不能有异常声明。
3. .this 与 .new
.this
用于生成对该内部类的外部类的对象的引用。
.new
用于生成对该外部类的内部类的对象的引用。
4.穿透现象
1、switch的穿透性能解决的问题
存在多个case分支的功能代码是一样时,可以用穿透性把流程集中到同一处处理,这样可以简化代码
2、例如:
跳转控制语句
break:跳出并结束当前所在循环的执行
continue:跳出当前循环的当次执行,进入本循环的下一次循环
5.捕获异常与重新抛出
当有多个 catch 时,只要其中一个捕获到异常,就会终止方法,接下来的 catch 不会继续执行。
抛出异常的时候,异常处理系统会按照代码的书写顺序匹配最近的处理程序。
子类对象可以匹配其基类的处理程序。
无论异常是否发生,finally 块总会执行,即使是涉及到 break 、 continue 和 return 时也会执行。
在 catch 中将当前异常对象重新抛出时,printStackTrace()方法显示的是原来的异常抛出点的调用栈信息,而非重新抛出点的信息。
想要更新这个信息,可调用fillInStackTrace()方法,这将返回一个Throwable对象,它把当前调用栈信息填入原来的异常对象。
6.格式化输出
在Java SE5中推出了c语言中printf()风格的格式化输出功能。
System.out.format()与System.out.printf()是等价的,它们的参数语法兼容与c语言语法。
Formatter.format()接受与printf()相同的参数并将信息输出到System.out。
String.format()是一个 static 方法,该方法接受与printf()相同的参数但返回一个String对象
7.多继承和向上转型
只可以继承一个类但可以实现多个接口。
implements 关键字要放在 extends 关键字后面,多个接口之间用”逗号”隔开。
实现多个接口的子类可以向上转型为每个接口类型。
接口可以继承(extends)多个接口,每个接口间使用逗号”隔开”。
实现多个接口时应尽量避免接口中含有同名方法
8.final
java中 final 常量只能是基本数据类型,并且在定义时即赋值(或定义空白 final 然后在构造器中赋值)。
一个即使 static 又是 final 的域只能占据一段不能改变的存储空间。
对于 final 引用,final 只是使引用恒定不变,即不能再使引用指向别的对象,而被引用的对象自身是可以修改的 。
final 参数:参数在该方法中只读,方法无法更改参数引用所指向的对象,通常用于向匿名内部类传递数据。
只有在想要明确禁止覆盖时才使用 final 方法,不要使用 final 来提升方法效率。
9.try{}finally{}和主动清理
无论 try
中的子句如何退出, finally
中的子句一定会执行(没有 catch
)。
可以在 finally
中定义一些清理方法,不要使用 finalize()
方法。
10.finalize()
该函数不等同于析构函数!
如果定义了该函数,那么一旦垃圾回收器准备好释放对象占用的内存空间,将首先调用其 finalize()
方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
11.为什么 typeof null === object
原理是这样的,不同的对象在底层都表示为二进制,在JavaScript中二进制前三位都为0的话会被判断为 obiect 类型,null 的二进制表示是全0,自然前三位也是0,所以执行 typeof 时会返回”object”。
12.注解
Java 中有以下几个元注解:
@Target:注解的作用目标
@Retention:注解的生命周期,与JVM有关
@Documented:注解是否应当被包含在 JavaDoc(API) 文档中
@Inherited:是否允许子类继承该注解
Java 3大内置注解:
@Override,@Deprecated,@SuppressWarnings
Class类通过实现AnnotatedElement接口来反射注解:Java反射机制解析注解主要是通过java.lang.reflect包下的提供的AnnotatedElement接口,Class<T>实现了该接口定义的方法,返回本元素/所有的注解(Annotation接口)。
反射注解的工作原理:
1)首先,我们通过键值对的形式可以为注解属性赋值,像这样:@Hello(value = "hello")。
2)接着,你用注解修饰某个元素,编译器将在编译期扫描每个类或者方法上的注解,会做一个基本的检查,你的这个注解是否允许作用在当前位置,最后会将注解信息写入元素的属性表。
3)然后,当你进行反射的时候,虚拟机将所有生命周期在 RUNTIME的注解取出来放到一个 map 中,并创建一个 AnnotationInvocationHandler 实例,把这个 map 传递给它。
4)最后,虚拟机将采用 JDK 动态代理机制生成一个目标注解的代理类,并初始化好处理器。
Java的Annotation注解,可参考十分钟深度学习Java注解
Note:RetentionPolicy.SOURCE注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
注解处理器(APT,javac自带的一个工具),可参考【Annotation】Processing-Tool详解
junit中常见注解(@Before即每个@Test测试方法都会运行一次),可参考JUnit详解
13.字符串
String对象是不可改变的,String类中每个会修改String值的方法,都会创建一个新的String对象,以包含修改后的字符串内容。
String对象作为方法参数时,传递的是引用的一个拷贝,方法不会对原来的String对象产生影响。
StringBuffer与StringBuilder是可变的有序字符串序列,StringBuffer是线程安全的,StringBuilder不是线程安全的。
在字符串不经常变化的场景使用String。
在频繁进行字符串运算的多线程环境中使用StringBuffer。
在频繁进行字符串运算的单线程环境中使用StringBuilder。
14.字符型常量和字符串常量的区别?
1.形式 : 字符常量是单引号引起的一个字符,字符串常量是双引号引起的 0 个或若干个字符。
2.含义 : 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)。
3.占内存大小 : 字符常量只占 2 个字节; 字符串常量占若干个字节。
15.标识符和关键字的区别是什么?
在我们编写程序的时候,需要大量地为程序、类、变量、方法等取名字,于是就有了 标识符 。简单来说, 标识符就是一个名字 。
16.Java 语言关键字有哪些?
Tips:所有的关键字都是小写的,在 IDE 中会以特殊颜色显示。
default 这个关键字很特殊,既属于程序控制,也属于类,方法和变量修饰符,还属于访问控制。
在程序控制中,当在 switch 中匹配不到任何情况时,可以使用 default 来编写默认匹配的情况。
在类,方法和变量修饰符中,从 JDK8 开始引入了默认方法,可以使用 default 关键字来定义一个方法的默认实现。
在访问控制中,如果一个方法前没有任何修饰符,则默认会有一个修饰符 default,但是这个修饰符加上了就会报错。
⚠️注意 :虽然 true, false, 和 null 看起来像关键字但实际上他们是字面值,同时你也不可以作为标识符来使用。
17.自增自减运算符
在写代码的过程中,常见的一种情况是需要某个整数类型变量增加 1 或减少 1,Java 提供了一种特殊的运算符,用于这种表达式,叫做自增运算符(++)和自减运算符(–)。
++ 和 – 运算符可以放在变量之前,也可以放在变量之后,当运算符放在变量之前时(前缀),先自增/减,再赋值;当运算符放在变量之后时(后缀),先赋值,再自增/减。
例如,当 b = ++a 时,先自增(自己增加 1),再赋值(赋值给 b);当 b = a++ 时,先赋值(赋值给 b),再自增(自己增加 1)。也就是,++a 输出的是 a+1 的值,a++输出的是 a 值。用一句口诀就是:“符号在前就先加/减,符号在后就后加/减”。
18. 静态方法为什么不能调用非静态成员?
这个需要结合 JVM 的相关知识,主要原因如下:
1.静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
2.在类的非静态成员不存在的时候静态成员就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
19. 静态方法和实例方法有何不同?
1、调用方式
在外部调用静态方法时,可以使用 类名.方法名 的方式,也可以使用 对象.方法名 的方式,而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象 。
不过,需要注意的是一般不建议使用 对象.方法名 的方式来调用静态方法。这种方式非常容易造成混淆,静态方法不属于类的某个对象而是属于这个类。
因此,一般建议使用 类名.方法名 的方式来调用静态方法。
2、访问类成员是否存在限制
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制。
20.public,protected,private,default
public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不
仅可以跨类访问,而且允许跨包(package)访问。
private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以
及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、
属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问
区别:
1. public:可以被所有其他类所访问。
2. private:只能被自己访问和修改。
3. protected:自身,子类及同一个包中类可以访问。
4. default(默认):同一包中的类可以访问,声明时没有加修饰符,认为是friendly。
注意:
在继承的时候,他们的区别:
public 声明的在子类变为public
protected 声明的子类变为private
private 声明的在子类中不可用