天天看点

JavaSE学习笔记(9.Java中的修饰符)

1.Java关键词:

Java有50个关键词分别如下表:

JavaSE学习笔记(9.Java中的修饰符)

其中条件分支相关的有17个:if、else、do、while、for、continue、break、switch、case、throw、throws、try、catch、finally、goto(预留)、assert、return

包相关2个:import、package

类型相关10个:void、byte、char、short、int、long、boolean、float、double、enum

类相关的8个:new、class、extends、interface、implements、this、super、instanceof

修饰词的有13个:private、protected、default、public、abstract、static、final、transient、const(预留)、native、strictfp、volatile、synchronized

2.修饰符分类:

2.1 private、protected、默认包访问描述符(省略)、public用于描述作用域:

1. 修饰外部类(包括普通类、枚举类、抽象类、接口):只可以使用public和默认描述符修饰!

                      public描述符:包外作用域及包内作用域,都可以访问类

                      默认描述符 : 包内作用域,可以访问类

2. 修饰类内成员(各种内部类、静态非静态成员方法及变量、构造器):可以使用public、protected、默认修饰符、private修饰!

                      public修饰符:包内外全局均可以访问!

                      protected修饰符:包内全作用域及包外子类内作用域可以访问!

                      默认修饰符:包内全作用域!

                      private修饰符:类内作用域!

Ps:

  • 类内成员作用域一定要小于类的作用域,因为类内成员一定不会被大于类作用域的作用域访问到!如默认作用域的类中的public修饰的成员,就不会被包外作用域访问到!
  • 类成员和非类成员并不会影响成员的作用域,仅仅影响成员的访问方式而已(类访问、实例访问)!
  • 抽象类中的抽象方法不可以是private属性的,因为抽象方法需要重写,private属性的方法无法类外访问,无法重写!
  • 当类有且只有一个private属性的构造器的时候,该类应该被final属性修饰,因为该类无法在子类构造器中调用父类构造器,所以无法继承!
  • 子类重写父类方法的时候,作用域只可以增大不可以变小
  • 接口中所有成员(类成员变量、抽象方法、default方法、static方法、各种内部类)都是public访问属性,默认不填的编译器会默认补充为public属性!
  • 接口中的抽象方法,如果修饰作用域必须使用public属性修饰,不可以使用其他修饰符!同时可以不写,编译器默认补充public、final、abstract修饰符!
  • 每一个Java文件最多只能有一个public属性的类,并且这个类名必须要和文件名一致!同样可以没有public属性的类,默认修饰符属性的类可以有多个,类名可以不与文件名一致!

2.2 final修饰符:

1. 修饰外部类(普通类、枚举类:编译器自动添加):final修饰外部类的时候,只能修饰普通类和枚举类,不能修饰接口、抽象类;被final修饰的普通类和枚举类不可以被继承!

2. 修饰类内成员(非内部接口/抽象内部类的各种内部类、类成员和实例成员方法及变量):                                            

     2.1 内部类:final修饰内部类表示该内部类不可以被继承; 此处主要注意局部内部类和匿名内部类的effectively final规则               

     2.2 类成员方法/实例成员方法:被修饰的方法在子类中不可以被重写,静态非静态规则一致!只有当private和final同时修饰方法的时候,可以无视final修饰符,因为子类中没有办法访问继承自父类的private属性方法,不会存在二义性!

     2.3 类成员变量:final修饰类成员变量,表示该类成员变量一旦被初始化(初始化可以在定义时完成,也可以在初始化代码块中完成)后,即不可再被修改!

     2.4 实例成员变量:final修饰实例成员变量,表示该实例成员变量一旦被初始化(初始化可以在定义时完成;也可以在构造器中完成,当构造器存在嵌套调用的时候,只能在最早被调用的构造器中定义)后,即不可再被修改!

Ps:final修饰类成员变量和实例成员变量的原则,变量值不随着实例创建而改变的均设计为final static属性,在类创建的时候赋值;变量随着实例创建而改变的(在构造方法中初始化不同值的情况)设计为final属性!

3. 修饰局部变量:final修饰局部变量,表示该局部变量一旦被初始化(初始化可以在定义时完成,也可以在该局部变量使用前完成)后,即不可再被修改

4. 修饰形参:final修饰形参,表示该形参在方法内不可用改变引用指向或者值内容!

Ps:

  1. 当final修饰的变量在定义的时候初始化,并能够在编译的时候确定其值,则该变量会被编译成为宏变量(常量值)!
  2. Java语言规范中,只有final修饰符可以修饰形参,但final修饰符不参与形参类型是否一致的判断(只有形参个数和形参类型参与判断)!

2.3 static修饰符:

1. 修饰类内成员(静态内部类、类成员方法和变量、类初始化块):使得被修饰的内容隶属于类,通过类进行访问及初始化!

Ps:类方法、类成员变量、内部类均可以继承;类方法还可以被重写!(说明子类中均具备父类的类成员)

很多地方通过类方法无法多态来描述类方法不可以重写,但是个人认为最直接的说明问题的还是final修饰符,原本可以重写的类方法,在父类中增加final修饰符,会导致编译报错!

package Grpc_Test.GrpcProject;

public class Test 
{
	public static void main( String[] args )
	{
		
	}
	
	public static final void fun()
	{
		
	}
}

class TestSon extends Test
{
        //编译报错!!!
	public static void fun()
	{
		
	}
}
           

编译器报错说明:

JavaSE学习笔记(9.Java中的修饰符)

2.4 abstract修饰符:

1. 修饰外部类(只能修饰抽象类和抽象枚举类:编译器自动添加;不能修饰接口、普通类):表示该类为抽象类,不可实例化,类中可以存在抽象方法!

2. 修饰类内成员(抽象方法、抽象内部类):

2.1 抽象方法:abstract修饰成员方法,表示该方法为抽象方法,不可以有方法体!抽象方法比较特殊,因为抽象方法没有方法体,不能完成类方法访问!所以不能被static修饰;同时抽象类不能实例化,导致这个方法有不是实例方法!

Ps:抽象方法只有被子类继承才有存在的意义,所以抽象方法不能被private修饰或者final修饰!

2.2 抽象内部类(静态内部类、非静态内部类、局部内部类):abstract不可以修饰匿名内部类,因为匿名内部类需要实例化!   

public abstract class TestAbstract {
		
	/*abstarct修饰静态内部类*/
	public abstract static class inclass1
	{
		
	}
	
	/*abstract修饰非静态内部类*/
	public abstract class inclass2
	{
		
	}
	
	public void fun()
	{
		/*abstract修饰局部内部类*/
		abstract class inclass3
		{
			
		}
	}
	
}
           

Ps:abstract不可以与final共存!!!

2.5 default修饰符:

只作为接口中默认方法修饰符使用,不可以与static共存!!!详细描述见JavaSE学习笔记(5.抽象类与接口)

2.6 transient修饰符(具体细节在序列化章节补充):

transient修饰类变量和成员变量,表示在序列化的时候,忽略该变量!

2.7 native修饰符(具体现实细节后面补充):

native只能修饰方法,用作JNI(Java Native Interface);同样native修饰的方法没有方法体,表示通过Java调用C/C++实现的代码(C/C++需要编译成为DLL文件,被Java加载调用)!

Ps:native实现过程:

  1、在Java中声明native()方法,然后编译;

  2、用javah产生一个.h文件;

  3、写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件);

  4、将第三步的.cpp文件编译成动态链接库文件;

  5、在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native()方法就可以在Java中被访问了。

2.8 strictfp修饰符:

修饰类(各种外部类、各种内部类包括枚举)、成员方法、类方法、成员变量、类变量:用来指示被修饰范围内的Java的编译器和运行环境完全按照浮点型规范IEEE-754来执行(Java的浮点运算是做过优化的)!

2.9 volatile修饰符(具体细节线程章节补充):

修饰线程共享变量(类变量、实例成员变量),保证变量的可见性、有序性:

1. 在JMM模型中,被volatile修饰的线程共享变量,不进行线程内数据缓存,会将线程本地变量内存值的改变迅速覆盖主内存中去,并将其他线程中的该变量内存的缓存设置为过期!进而完成线程A中的数据改变传递给线程B!当然不设置volatile就存在可缓存,可不缓存的歧义场景!

2.被volatile修饰的变量,会在一定规则的程度下禁止指令重排序优化!详细规则见<Java中的volatile>

2.10 synchronized修饰符(具体细节线程章节补充):

1. 类内成员(修饰实例方法和类方法):修饰同步方法,如果该方法是实例方法则默认的同步监视器为this;如果该方法为类方法则默认的同步监视器为(xxx.class对象)!

2. 修饰同步代码块:表示修饰的代码块,在并发的时候需要通过抢占同步监视器来获得访问权限!

2.11 接口中修饰符使用约束:

1. 对于接口的访问权限修饰符只能是public和默认包访问权限!

2. 接口中的成员只能有,类常量(final static)、类方法(static)、默认方法(default)、抽象方法(abstract)、内部类(内部接口、内部枚举、抽象内部类、内部类);注意接口中无构造器和初始化块!

3. 接口中的所有成员都是public属性,可以明确定义,也可以省略,编译器自动补充!

4. 接口中的类常量只能是public static final属性,同样这三个修饰符都可以省略,编译器可自动补充!

5. 接口中的抽象方法只能是public abstract属性,同样对于没有方法体的方法,可以省略这两个修饰符,编译器可自动补充!

6. 接口中的各种内部类只能是public static属性,同样这两个修饰符可以省略,编译器可自动补充!

3.修饰符对成员方法重写的影响:

子类方法被认定为父类方法的重写方法原则:方法名相同、方法参数类型相同(作用域修饰符、static、final都不能作为判断依据)!!!

3.1 作用域修饰的影响:为了保证通过父类可以顺利调用子类中的继承重写的父类方法;必须保证子类重写父类的方法的时候,修饰符作用域一定大于父类方法作用域修饰符!否则当方法被认定为是重写方法的时候,则会报错!!!

public class Test 
{
	public void fun()
	{
		
	}
}

class TestSon extends Test
{
	/*编译报错*/
	private void fun()
	{
		
	}
}
           

3.2 static修饰符的影响:静态方法可以重写静态方法,实例方法可以重写实例方法;一旦子类方法被认定为重写方法,存在静态方法与实例方法交叉重写的情况,编译会报错!!!

Ps:静态方法可以被子类重写,但是不能构成多态!即通过子类访问的静态方法为子类的静态方法;通过父类访问的静态方法为父类的静态方法,即使父类的真实类型是子类类型,调用的也是父类的静态方法!

示例:

public class Test 
{
	public static void fun()
	{
		System.out.println("Test fun()");
	}
	
	public static void main(String args[])
	{
		Test t1 = new Test();
		t1.fun(); //Test fun()
		
		TestSon t2 = new TestSon();
		t2.fun(); //TestSon fun()
		
		t1 = t2;
		t1.fun(); //Test fun()
	}
}

class TestSon extends Test
{
	public static void fun()
	{
		System.out.println("TestSon fun()");	
	}
}
           

3.3 final修饰符的影响:不管是静态方法还是实例方法,只要被final修饰,都不能实现方法重写,否则编译报错!

4.修饰符访问范围表:

JavaSE学习笔记(9.Java中的修饰符)

5.修饰符定义顺序原则:

在Java语言规范中,描述Class Modifiers(8.1.1)、Field Modifiers(8.3.1)、Method Modifiers(8.4.3)、Constructor Modifiers(8.8.3)

JavaSE学习笔记(9.Java中的修饰符)
JavaSE学习笔记(9.Java中的修饰符)
JavaSE学习笔记(9.Java中的修饰符)
JavaSE学习笔记(9.Java中的修饰符)

6.关键字补充说明:

6.1 assert:

Java的断言功能,应该是从C/C++衍生过来的功能,在调试场景中使用,需要通过-ea开关进行打开关闭!

assert true; //程序正常运行

assert false:"Err Msg"; //程序停止并输出Err Msg

6.2 instanceof (后面章节补充与isInstance()区别):

instanceof关键字是用来,指出一个对象是否为一个类的实例,是返回true,不是返回false

示例:result = object instanceof class

在编译态:class可以是object的父类、自身类、子类,编译都会成功!

在运行态:class是object的父类、自身类,结果返回true;class是object的子类,结果返回false!

7.文件名、类名、main方法之间的关系:

1. 一个文件内可以定义多个类,可以都是包访问权限,但最多只能有一个public属性,并且public属性的类名必须和文件名一致!

2. main方法(方法名区分大小写,必须是小写),方法属性必须是public static void属性,参数必须是字符串数组(String args[]);所属于的类可以是public访问权限也可以是包访问权限,而且任何类都可以定义main方法!

继续阅读