目录
标识符和关键字的区别是什么?
在我们编写程序的时候,需要大量地为程序、类、变量、方法等取名字,于是就有了标识符,简单来说,标识符就是一个名字。但是有一些标识符,Java 语言已经赋予了其特殊的含义,只能用于特定的地方,这种特殊的标识符就是关键字。因此,关键字是被赋予特殊含义的标识符。比如,在我们的日常生活中 ,“警察局”这个名字已经被赋予了特殊的含义,所以如果你开一家店,店的名字不能叫“警察局”,“警察局”就是我们日常生活中的关键字。
Java 中有哪些常见的关键字?
分类 | 关键字 | ||||||
---|---|---|---|---|---|---|---|
访问控制 | private | protected | public | ||||
类,方法和变量修饰符 | abstract | class | extends | final | implements | interface | native |
new | static | strictfp | synchronized | transient | volatile | ||
程序控制 | break | continue | return | do | while | if | else |
for | instanceof | switch | case | default | |||
错误处理 | try | catch | throw | throws | finally | ||
包相关 | import | package | |||||
基本类型 | boolean | byte | char | double | float | int | long |
short | null | true | false | ||||
变量引用 | super | this | void | ||||
保留字 | goto | const |
权限修饰符简介
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
-
default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
-
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
-
public : 对所有类可见。使用对象:类、接口、变量、方法
-
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
基本就是public > protected > default > private
权限是 本类(都行) > 同包(同包子类或者同包其他类,private不行) > 子类(这种说的是其他包的子类,default又不行了) > 其他包(protected又不行了,只能public)
protected对应子类与包
default对应包
实例-方法字段
基类
可以看到在本类中,4种都能用
package test.t11quanxian.basepackage;
public class Base {
public String publicString="publicString";
protected String protectedString="protectedString";
String defaultString="defaultString";
private String privateString="privateString";
public void printpublic(){
System.out.println("printpublic");
}
protected void printprotected(){
System.out.println("printprotected");
}
void printdefault(){
System.out.println("printdefault");
}
private void printprivate(){
System.out.println("printprivate");
}
public void test(){
Base base=new Base();
System.out.println(base.publicString);
base.printpublic();
System.out.println(base.protectedString);
base.printprotected();
System.out.println(base.defaultString);
base.printdefault();
System.out.println(base.privateString);
base.printprivate();
}
public static void main(String[] args) {
new Base().test();
}
}
本包
本包子类
只有private不行
本包其他类
也是只有private不行
其他包
其他包子类
default和private不行,只能protected和public
注意:调用protected的要super.xxx来调用,不能引用base.xxx,原因如下:
protected 需要从以下两个点来分析说明:
-
子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;
-
子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。
其他包其他类
只能public
实例-类
类-public
类-default
本包内测试
两个类都能创建,而且不用import
其他包测试
只能创建public的,不能创建default的,而且import这个类都不行
权限修饰符总结
4种权限修饰符
1、public修饰成员方法
包内:可以在包中任意类中直接创建该方法所在类或子类的对象进行方法的调用;
包外:可以在包外任意类中直接创建该方法所在类或子类的对象进行方法的调用。
包修饰符:被声明为 public 的类和接口能够被任何其他类访问。如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。
2、protected修饰成员方法:最想写的就是这个修饰符,它是专门为子类所提供的一个权限修饰符。
包内:可以在包中任意类中直接创建该方法所在类或子类的对象进行方法的调用;
包外:只能创建该方法所在类的子类的对象进行方法的调用,而且子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。方法所在类的对象无法进行调用。
3、default修饰成员方法:则该外方法相当于被封装在包内了。
包内:可以在包中任意类中直接创建该方法所在类或子类的对象进行方法的调用;
包外:无法访问该方法。
包修饰符:被声明为 default 的类只能在本包内被访问,创建,在其他包内,不能被导入和创建
4、private修饰成员方法:则该外方法相当于被封装在类中了。
包内:仅在方法所在类中可以被访问,包中其他类也无法访问;
包外:无法访问该方法。
外部包的调用情况
1 包修饰符:外部类仅能被public和default修饰。倘若外部类被default修饰则只能在包内中进行访问;被public修饰既能在包内中进行访问也能在包外访问,在包外出现时必须带上包名,否则就导包。
2 成员,方法修饰符:可以被4中权限修饰符所修饰,由大到小依次为public、protected、default、private。其中该成员若想在包外被调用,则只能用public和protected权限修饰符所修饰。包外:成员被public修饰时,方法所在类的对象和子类的对象都能调用;成员被protected修饰时,只有子类的对象能调用。
内部包的调用情况
1 包修饰符:外部类仅能被public和default修饰。public和default都能访问
2 成员,方法修饰符:即只有private的不能访问,default和protected的都能被访问
final关键字
final关键字主要用在三个地方:变量、方法、类。
1 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
2 当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。
3 使用final方法的原因有两个。
第一个原因是把方法锁定,以防任何继承类修改它的含义;
第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了) 。类中所有的private方法都隐式地指定为final
final变量的初始化
被final修饰而没有被static修饰的类的属性变量只能在两种情况下初始化:
1) 在它被定义的时候
public class Test{
public final int a=0;
private Test(){
}
}
2) 在构造函数里初始化
public class Test{
public final int a;
private Test(){
a=0;
}
}
当这个属性被修饰为final,而非static的时候,它属于类的实例对象的资源,当类被加载进内存的时候这个属性并没有给其分配内存空间,而只是定义了一个变量a,只有当类被实例化的时候这个属性才被分配内存空间,而实例化的时候同时执行了构造函数,所以属性被初始化了,也就符合了当它被分配内存空间的时候就需要初始化,以后不再改变的条件。
注意:
考虑到一个类中的构造方法可能有多个因素, 加入了一个无参的构造方法
可以发现添加无参构造方法之后, 编译直接报错了, 但是如果在无参构造方法中对final修饰的字段进行显式赋值, 则编译又可以通过了.
于是我得出了个人的一个结论:final修饰的非静态的字段, 在虚拟机为它开辟空间时必须得保证它会被显式赋值一次且只被赋值一次, 不管是在初始化块时, 显式初始化时, 还是构造方法初始化时
也就是说如果在在初始化块中对final修饰的字段进行了初始化, 那么就不能进行显示初始化, 也不能使用构造方法初始化, 如果在定义字段时就显式赋值了, 那么同理不能进行初始化块初始化和构造方法初始化, 以此类推(3选一赋值)
但是使用构造方法初始化时, 要注意必须在每一个构造器中都对final修饰的字段初始化, 不然就存在该字段可能没有赋值的可能
同时被final和static修饰的类的属性变量只能在两种情况下初始化:
1) 在它被定义的时候
public class Test{
public static final int a=0;
private Test(){
}
}
2) 在类的静态块里初始化
public class Test{
public static final int a;
static{
a=0;
}
}
当类的属性被同时被修饰为static和final的时候,他属于类的资源,那么就是类在被加载进内存的时候(也就是应用程序启动的时候)就要为属性分配内存,所以此时属性已经存在,它又被final修饰,所以必须在属性定义了以后就给其初始化值。而构造函数是在当类被实例化的时候才会执行,所以不能用构造函数。而static块是类被加载的时候执行,且只执行这一次,所以在static块中可以执行初始化。