Java修饰符

一、访问修饰符

1.顾名思义,"访问修饰符"就是和访问权限有关得修饰符。

JAVA 的类(外部类)有 2 种访问权限: public、default。

而方法和变量有 4 种:public、default、protected、private。

其中默认访问权限和 protected 很相似,有着细微的差别。

  •  public 意味着任何地方的其他类都能访问。
  •  default 则是同一个包的类可以访问。
  •  protected 表示同一个包的类可以访问,其他的包的该类的子类也可以访问。
  •  private 表示只有自己类能访问。

2.这里重点说一下受保护的访问修饰符-protected

protected 需要从以下两个点来分析说明:

  • 子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;

  • 子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。

package p1;
public class Father1 {
    protected void f() {}    // 父类Father1中的protected方法
}
 
package p1;
public class Son1 extends Father1 {}
 
package p11;
public class Son11 extends Father1{}
 
package p1;
public class Test1 {
    public static void main(String[] args) {
        Son1 son1 = new Son1();
        son1.f(); // Compile OK     ----(1)
        son1.clone(); // Compile Error     ----(2)
 
        Son11 son = new Son11();    
        son11.f(); // Compile OK     ----(3)
        son11.clone(); // Compile Error     ----(4)
    }
}

对于上面的示例,首先看(1)(3),其中的f()方法从类Father1继承而来,其可见性是包p1及其子类Son1和Son11,而由于调用f()方法的类Test1所在的包也是p1,因此(1)(3)处编译通过。其次看(2)(4),其中的clone()方法的可见性是java.lang包及其所有子类,对于语句"son1.clone();"和"son11.clone();",二者的clone()是继承了Object类的方法,在类Son1、Son11中是可见的,但对Test1是不可见的,因此(1)(3)处编译不通过。

package p2;
class MyObject2 {
    protected void say() {
       System.out.println("我是父类的say方法!")
    }
}
 
package p22;
public class Test2 extends MyObject2 {
    public static void main(String args[]) {
       MyObject2 obj = new MyObject2();
       obj.say(); // Compile Error         ----(1)
 
       Test2 tobj = new Test2();
       tobj.say(); // Complie OK         ----(2)
    }
}

对于(1)而言,say()方法来自于类MyObject2本身,因此其可见性为包p2及MyObject2的子类,虽然Test2是MyObject2的子类,但在Test2中不能访问基类MyObject2的protected方法say(),因此编译不通过;对于(2)而言,由于在Test2中访问的是其本身实例的从基类MyObject2继承来的的say(),因此编译通过。

 

3.访问修饰符中一些值得注意得地方:

Private 访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据;

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问;

protected 访问修饰符不能修饰类和接口,方法和成员变量能够声明为 protected,但是接口的成员变量和成员方法不能声明为 protected;

 

二、非访问修饰符

1.abstract

可以修饰:方法  类   接口 

【抽象类】
 ①.使用abstract关键字修饰类,称为抽象类
 ②.抽象类不能被实例化
 【抽象方法】
 ①.被abstract修饰的没有方法体的方法
 ②.非抽象类继承抽象类,那么子类必须重写父类所有的抽象方法
 ③.抽象方法必须在抽象类中,但抽象类中不都是抽象方法

【接口】

①接口定义时使用interface关键字,默认用abstract修饰此关键字了;

②接口里的方法即使不写abstract依然是抽象方法,因为默认使用abstract修饰

2.static

可以修饰: 方法 属性  内部类(不可修饰外部类)

①.static修饰的属性 (静态属性)也叫类属性
②.static修饰的方法(静态方法)也叫类方法
③.推荐使用:类名.属性名 类名.方法名()来调用   (也可以使用对象调用)但不推荐
④.类属性和类方法是属于类的,在类加载时就加载,成员属性和成员方法在对象创建时才加载
 因此静态属性和静态方法先于非静态属性和方法, 所以静态方法中不能调用非静态属性,非静态方法可以调用静态属性
⑤.静态方法不能使用this,super关键字;因为他两个代指子类对象和父类对象而静态比对象加载的早

⑥.由于类属性和类方法是属于类的,因此只会在类装载时产生一份,因此该类的多个实例只能使用同一个静态属性和方法(下面代码辅助理解该条)

public class Demo03_Static {
    //定义静态属性和静态方法
    public static int a = 1 ;
    public static void add() {
        a++;
    }
    //定义成员属性和方法
    public int b = 1;
    public void add1(){
        b++;
    }
}
public class Demo03_Static2 {
    public static void main(String[] args) {
        //调用静态方法改变静态属性
        Demo03_Static d1 = new Demo03_Static();
        d1.add();//本来应该使用Demo03_Static.add();来调用静态方法这里为了方便理解没有使用
        System.out.println(d1.a);//本来应该使用Demo03_Static.a;来调用静态属性
        Demo03_Static d2 = new Demo03_Static();
        d2.add();//同上
        System.out.println(d2.a);
        //调用成员方法改变成员属性
        System.out.println("----------------------------------");
        Demo03_Static d3 = new Demo03_Static();
        d3.add1();
        System.out.println(d3.b);
        Demo03_Static d4 = new Demo03_Static();
        d4.add1();
        System.out.println(d4.b);
        
    }
}

运行结果:

※⑦.父类中的静态方法可以被继承、但不能被子类重写。

※⑧.如果在子类中写一个和父类中一样的静态方法,那么该静态方法由该子类特有,两者不构成重写关系。

public class Demo03_Static {
    //定义静态属性和方法
    public static int a = 1 ;
    public static void add() {
        a++;
        System.out.println("父类的静态方法!");
    }
}
public class Demo03_StaticSon extends Demo03_Static{
    
    public static void add(){//√,是子类自己的静态方法,和父类的方法不构成重写
        System.out.println("调用子类和父类同名的静态方法");
    }
    
    /*public void add(){//×,不能和父类静态方法重名
}
*/ public static void main(String[] args) { Demo03_Static d = new Demo03_StaticSon(); d.add();//测试能否重写父类的静态方法(多态本来是调用子类重写的父类方法,但是若调用父类自己的方法,说明没有重写该方法); } }

运行结果:

 

3. final

可以修饰:方法  属性  局部变量  类(非抽象类)

1.final修饰的类为最终类,不能被继承

2.final修饰的方法不能被重写,但可以被继承

3.final修饰的变量不能被修改为常量

4.final以及final static修饰的变量的初始化方式:

 //-----------------成员变量------------------//  
    //初始化方式一,在定义变量时直接赋值  
    private final int i = 3;  
  
    //初始化方式二,声明完变量后在构造方法中为其赋值  
    //如果采用用这种方式,那么每个构造方法中都要有j赋值的语句  
    private final int j;  
  
    public FinalTest() {  
        j = 3;  
    }  
  
    //如果取消该构造方法的注释,程序就会报错,因此它没有为j赋值  
    /*public FinalTest1(String str) { 
 
    }*/  
  
    //为了方便我们可以这样写  
    public FinalTest(String str) {  
        this();  //调用无参构造器
    }  
  
    //下面的代码同样会报错,因为对j重复赋值  
    /*public FinalTest1(String str1, String str2) { 
        this(); 
        j = 3; 
    }*/  
  
  
    //初始化方式三,声明完变量后在构造代码块中为其赋值  
    //如果采用此方式,就不能在构造方法中再次为其赋值  
    //构造代码块中的代码会在构造函数之前执行,如果在构造函数中再次赋值,  
    //就会造成final变量的重复赋值  
    private final int k;  
  
    {  
        k = 4;  
    }  
  
    //-----------------类变量(静态变量)------------------//  
    //初始化方式一,在定义类变量时直接赋值  
    public final static int p = 3;  
  
    //初始化方式二,在静态代码块中赋值  
    //成员变量可以在构造函数中赋值,但是类变量却不可以。  
    //因此成员变量属于对象独有,每个对象创建时只会调用一次构造函数,  
    //因此可以保证该成员变量只被初始化一次;  
    //而类变量是该类的所有对象共有,每个对象创建时都会对该变量赋值  
    //这样就会造成变量的重复赋值。  
    public final static int q;  
  
    static {  
        q = 3;  
    }

 

posted on 2018-04-08 19:56  ★【金字塔】☆  阅读(255)  评论(0编辑  收藏  举报