Java(11)Java修饰符
Java修饰符
Java修饰符分为两大类:
- 访问修饰符:default、private、public、protected
- 非访问修饰符:static、final、abstract、synchronized和volatile
访问修饰符
- public(修饰类、变量、方法、接口)
- default(修饰类、变量、方法、接口)
- private(修饰
类、变量、方法、接口) - protected(修饰
类、变量、方法、接口)//被划掉的不能被修饰
private-->default-->protected-->public (访问权限大小)
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | ✅/❌ | ❌ |
default(缺省) | ✅ | ✅ | ✅ | ❌ | ❌ |
private | ✅ | ❌ | ❌ | ❌ | ❌ |
访问修饰符是用来控制被修饰的东西的访问权限的,下面是访问修饰符的访问控制表:
可以看到,从private到default到protected到public,权限是越来越大的。private给予的权限最小,只有当前类可以使用。
private访问修饰符
修饰对象:private用来修饰变量和方法
范围:被private修饰的变量和方法只能为当前类使用
声明为private的变量只能通过类中公共的 getter 方法被外部类访问,如:
- Inner.java源文件(与下面文件在同一个包中)
public class Inner {
private int age=23;
public void SetAge(int age) {
this.age=age;
}
public int GetAge() {
return age;
}
}
- Outter.java源文件:
public class Outter{
public static void main(String[] args) {
Inner a= new Inner();
a.SetAge(50); //Outter类修改Inner类private声明的变量
System.out.println(a.GetAge()); //访问private声明的变量
}
}
default访问修饰符(缺省)
修饰对象:default用来修饰类、变量、方法、接口
范围:被private修饰的变量和方法只能为同一个包的类(包括子孙类)使用
- 缺省修饰的变量不能被外包类访问案例
package PackageOne;
public class HelloOne {
int age=21;
}
package PackageTwo;
import PackageOne.HelloOne;
public class HelloTwo extends HelloOne {
public static void main(String[] args) {
HelloTwo b=new HelloTwo();
System.out.println(b.age);
//报错:'age' is not public in 'PackageOne.HelloOne'. Cannot be accessed from outside package
}
}
protected访问修饰符
protected可修饰变量、方法(包括构造方法),不能修饰类。
1、子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;
2、子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。
- 案例
package p1;
public class Father1 {
protected void f() {
System.out.println("这是来自父类protected声明的方法");
}
}
//------------------------------
package p1;
public class Son1 extends Father1 {
public static void main(String[] args) {
Father1 a=new Father1();
a.f(); //输出:这是来自父类protected声明的方法
Son1 b=new Son1();
b.f(); //输出:这是来自父类protected声明的方法
}
}
//-------------------------------
package p2;
import p1.Father1;
public class Son2 extends Father1{
public static void main(String[] args) {
Father1 a=new Father1();
//a.f(); 此步会编译报错(a是父类实例,而Son2子类与父类不在同一个包中)
Son2 b = new Son2();
b.f(); //输出:这是来自父类protected声明的方法
}
}
public访问修饰符
方法和属性前有public修饰,可以被任意包内的类访问。 另外,类要想被其他包导入,必须声明为public。被public修饰的类,类名必须与文件名相同。
非访问修饰符
static非访问修饰符
static
可以概括为一句话:方便在没有创建对象的情况下进行调用。也就是说:被static关键字修饰的不需要创建对象去调用,直接根据类名就可以去访问。
被static
修饰后的成员会随着类的加载而加载,优先于对象存在,被所有对象共享。
static
关键字修饰成员变量(不能修饰局部变量)、方法、代码块、内部类。
package test;
public class HelloJimmy {
public static int a = 10;
public static void fun1() {
System.out.println("Hello Krystal");
}
}
class Person {
public static void main(String[] args) {
//直接通过类名访问静态变量,如果a声明名中的static删掉,此步会报错
HelloJimmy.a = 20;
//通过创建对象进行调用,不推荐这样使用
HelloJimmy b = new HelloJimmy();
b.a = 30;
//通过类名直接访问静态方法,如果a声明名中的static删掉,此步会报错
HelloJimmy.fun1();
//通过创建对象访问
b.fun1();
}
}
静态变量
实例变量在每个实例中都有自己的一个独立“空间”,但是静态变量只有一个共享“空间”,所有实例都会共享该变量。对于静态变量,无论修改哪个实例的静态变量,效果都是一样的:所有实例的静态变量都被修改了,原因是静态变量并不属于实例。
package test;
public class TestOne {
public static void main(String[] args) {
HelloStatic a = new HelloStatic();
HelloStatic b = new HelloStatic();
a.setAge(20);//这步会同时改变b实例的age值
System.out.println(a.getAge());//结果为20
System.out.println(b.getAge());//结果也是20
}
}
class HelloStatic {
private static int age = 18;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
}
静态方法
用static修饰的方法称为静态方法,跟静态变量一样,静态方法属于class
而不属于实例,因此,静态方法内部,无法访问this变量,也无法访问实例字段,它只能访问静态字段。 需要的是,main()
方法就是静态方法。
package test;
public class TestOne {
private static int name;
HelloStatic c=new HelloStatic();
public static void main(String[] args) {
System.out.println(this.name);
//报错:'test.TestOne.this' cannot be referenced from a static context
System.out.println(c.getAge());
//报错:Non-static field 'c' cannot be referenced from a static context
}
}
class HelloStatic {
private static int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
}
静态方法如果要访问内部类,则该内部类需要加上static
修饰符。
public class TestOne {
public static void main(String[] args) {
Person a = new Person();
//报错:'test.TestOne.this' cannot be referenced from a static context
//提示:make Person ‘static’
}
class Person { //将Person这个内部类加上static修饰符即可被静态方法访问
private int age;
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
}
}
静态方法常用在工具类中,例如Math.random(); Arrays.sort();
package test;
class CompareM { //将CompareM作为一个比较大小的工具类
//选取最大值
public static int findMax(int a,int b){
return a>b?a:b;
}
//选取最小值
public static int findMin(int a,int b){
return a>b?b:a;
}
}
public class TestOne {
public static void main(String[] args) {
//下面使用工具类CompareM的静态方法
System.out.println(CompareM.findMax(54,23));
System.out.println(CompareM.findMin(3,744));
}
}
静态变量和静态方法的设计思想
类属性(类变量)作为该类各个对象之间共享的变量。在设计类时,分析哪些类属性不因对象的不同而改变,将这些属性设置为类属性。相应的方法设置为类方法。
如果方法与调用者无关,则这样的方法通常被声明为类方法,由于不需要创建对象就可以调用类方法,从而简化了方法的调用。
接口的静态变量
接口里面可以存在常量,修饰符默认为public static final
public interface Test01{
int a=10;//等同于public static final int a=10;
}
final非访问修饰符
- final修饰的类不能被继承。提高安全性,提高程序的可读性。
- final修饰的方法不能被子类重写。
- final修饰的变量(成员变量或者局部变量)即称为常量。变量名称通常用大写,且只能被赋值一次。
final修饰类
package test;
public final class Father{
}
class Son extends Father{
//会报错:Cannot inherit from final 'test.Father',表示Father类不能被继承
}
final修饰方法
package test;
public class Father{
public final String funFirst(){
return "True";
}
}
class Son extends Father{
@Override
public String funFirst() { //报错:'funFirst()' cannot override 'funFirst()' in 'test.Father'; overridden method is final,表示父类方法funFirst()不能被重写
return super.funFirst();
}
}
final修饰变量
package test;
public class Father{
public final static int a=20;
}
class Son extends Father{
public static void main(String[] args) {
a=30;//报错:Cannot assign a value to final variable 'a',表示不能修改a的值
}
}
final修饰的成员变量必须初始化值,可以直接赋值也可以在构造方法中赋初值(建议使用这种方式)。
public class Father{
public final int a;//会报错:Variable 'a' might not have been initialized
}
package test;
public class Father{
public final int a;//此处不能添加static,如果添加static必须通过直接赋值,不能用构造方法来赋初始值。final变量经常和static关键字一起使用,作为常量。
public Father(int a){
this.a=a;
}
}
class Son extends Father{
public Son(int a) { //必须显示调用super()方法
super(a);
}
}
class RunClass{
public static void main(String[] args) {
Son b=new Son(24);
System.out.println(b.a); //输出24
Father c=new Father(8);
System.out.println(c.a); //输出8
c.a=23; //被构造方法赋了初始值,不能被修改,会报错:Cannot assign a value to final variable 'a'
}
}
如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。