java 非访问修饰符

一、为什么会有非访问修饰符

    为了实现一些其他的功能,java提供了许多非访问修饰符

二、定义

  static 修饰符,用来修饰类方法和类变量。

  final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的

  abstract 修饰符,用来创建抽象类和抽象方法。

  synchronized 和 volatile 修饰符,主要用于线程的编程。

三、详解

 1.static

  ①优缺点

     优点不需要在进行实例化。静态变量的值,直接赋新值即可,不需要参数传递,之后可以直接进行参数引用即可;静态方法可以直接通过"类名.方法"的形式进行方法调用。通常方法被多次调用,并且方法中没有动态方法引用的时候使用比较方便。

     缺点初始化加载到内存,如果后续没被引用,加大了内存负担和程序运行负担,影响程序运行效率(一般很小),并且静态变量如果多处被引用赋值,很可能导致参数值混(如果是不变的值,最后加上final修饰,强制不能修改)

   ②使用地点

     静态变量:

              static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。

              静态方法:

              static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据

       ③代码

public class InstanceCounter {
   private static int numInstances = 0;
   protected static int getCount() {
      return numInstances;
   }
 
   private static void addInstance() {
      numInstances++;
   }
 
   InstanceCounter() {
      InstanceCounter.addInstance();
   }
 
   public static void main(String[] arguments) {
      System.out.println("Starting with " +
      InstanceCounter.getCount() + " instances");
      for (int i = 0; i < 500; ++i){
         new InstanceCounter();
          }
      System.out.println("Created " +
      InstanceCounter.getCount() + " instances");
   }
}
运行结果:
Starting with 0 instances
Created 500 instances

注:static作为静态成员变量和成员函数的修饰符,意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,其修改值为该类的其它所有实例所见。如果一个类要被声明为static的,只有一种情况,就是静态内部类如果在外部类声明为static,程序编译都不会过。

    2.final

  ①使用地点:它可以修饰非抽象类、非抽象类成员方法和变量

  final数据:  

   1.final成员变量必须在声明的时候初始化(static代码块和普通代码块)或者在构造器(构造函数)中初始化,否则就会报编译错误。 
         2.不能够对final变量再次赋值。 
         3.在匿名类中所有变量都必须是final变量。 
         4.(没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或者调用this()初始化。不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”。) 
         5.JVM和Java应用都会缓存final变量,以提高性能。 
         6.final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。

注:final指明数据为一个常量,恒定无法修改;static指明数据只占用一份存储区域;

       测试:

public class FinalData {  
    private final int valueOne = 3;  
    private int valueTwo = 4;  
    private final Value v1 = new Value(4);  
    private Value v2 = new Value(10);  
    private final int[] a = {1,2,3,4,5,6,7,8,9};  
    private int[] b = {1,2,3,4,5,6,7,8,9};  
    private static final int VAL_TWO = 3;  
      
    public static void main(String[] args) {  
        FinalData finalData = new FinalData();  
        /*-----------基本类型测试------------------------------------*/  
//      finalData.valueOne = 4;//valueOne是常量,无法修改  
        finalData.valueTwo = 14;//valueTwo不是常量,可以修改  
          
        /*-----------对象类型测试------------------------------------*/  
//      finalData.v1 = new Value(5);//v1对象是final型常量,其引用是无法修改的。  
        finalData.v2 = new Value(20);//v2对象final型常量,其引用可以修改。  
        finalData.v1.i = 5;//v1对象的成员变量不是final型,可以修改  
          
        /*-----------数组类型测试------------------------------------*/  
//      finalData.a = new int[3];//数组a是final型,无法修改a的引用  
        finalData.b = new int[13];//数组b不是final型,可以对其引用进行修改  
        for(int i=0;i<finalData.a.length;i++)   
            finalData.a[i]++;//数组a内部数据是int型,不是final型,可以修改  
          
        /*-----------static final类型测试------------------------------------*/  
//      finalData.VAL_TWO = 4;  
        //定义为private,只能被本类的方法调用;定义为static,则强调只有一份,且只被执行一次;定义为final,则说明它是一个常量,无法被修改。  
          
    }  
}

    final方法:

        1.一个方法的功能已经足够完整了,子类中不需要改变的话,就声明此方法为final。 
        2.final方法比非final方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。

public class Custom extends Person{
        public void method1(){
            System.out.println("Person's  method1....");
        }

    //    Cannot override the final method from person:子类不能覆盖父类的final方法
    //    public void method2(){
    //        System.out.println("Person's method2...");
    //    }
    }

    final类:

        final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。
    3.abstract

    ①使用地点修饰类和方法

        抽象类及抽象方法:

           抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。

public abstract class MyClass
{
   private String year;
   public abstract void abc(); //抽象方法
}

        实现:

public abstract class SuperClass{
    abstract void a(); //抽象方法
}
 
class SubClass extends SuperClass{
     //实现抽象方法
      void a(){
          .........
      }
}

        注意事项

        抽象类不能被实例化。
        抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类。
        如果子类没有实现父类中的抽象方法,子类必须定义为抽象类。
        抽象类不能被定义为private、final和static类型。
        没有抽象构造方法。
        抽象方法没有方法体。

        4.synchronized 

                synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。

public synchronized void showDetails(){
.......
}

        5.volatile

                volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

                    一个 volatile 对象引用可能是 null。


public class MyRunnable implements Runnable
{
    private volatile boolean active;
    public void run()
    {
        active = true;
        while (active) // 第一行
        {
            // 代码
        }
    }
    public void stop()
    {
        active = false; // 第二行
    }
}

            通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。


版权声明:本博客为记录本人自学感悟,内容大多从网上学习与整理所得,若侵权请告知!

https://mp.csdn.net/postedit/80365677




        


      

猜你喜欢

转载自blog.csdn.net/qq_39657909/article/details/80448956