关于Java中的访问控制与Static关键字

一、介绍

  先来介绍一下Java中的几个访问关键字,在此之前先来看一个场景:

  场景1:工程师A编写了一个类ClassA,但是工程师A并不希望ClassA被该应用中其他所用的类都访问到,那么该如何处理?

  场景2:如果工程师A编写了一个类ClassA,其中有两个方法fun1、fun2,工程师只想让fun1对外可见,也就是说,如果别的工程师来调用ClassA,只可以调用方法fun1,那么该怎么处理?

  此时,访问权限控制便可以起到作用了。

  在Java中,提供了四种访问权限控制:默认访问权限(包访问权限),public,private以及protected。

  注意,上述四种访问权限,只有默认访问权限和public能够用来修饰类。修饰类的变量和方法四种权限都可以。(本处所说的类针对的是外部类,不包括内部类)

  下面就分别针对修饰类和修饰类的成员来讲述这四种访问权限控制。

二、修饰类

  修饰类有两种情况:默认访问权限(包访问权限):表示该类的内容对同属于一个包里的对象都是可见的。

  Public访问权限:表示该类对其他所有类都可见。 下面举例子说明一下它们之间的区别:

mian.java:

1 package com.ztc;
2 import com.other.ceshi;//报错
3 import com.other.Publicceshi;
4 public class mian1 {
5     public static void main(String[] args) {
6         Dog x = new Dog();
7         x.x();
8     }
9 }

Dog.java:

1 package com.ztc;
2 
3  class Dog {//默认访问权限(包访问权限),和mian类在一个包下面
4     public void x(){
5         System.out.println("Dog");
6     }
7 }

ceshi.java:

1 package com.other;
2 
3 class ceshi//默认访问权限,包访问权限,但和mian类不在一个包下面
4 {
5     public void x(){
6         System.out.println("ceshi");
7 }
8 
9 }

Publicceshi.java:

1 package com.other;
2 
3 public class Publicceshi {//公开访问权限,和main类不在一个包下面
4     
5 }

 

可以看到mian包里在引用ceshi类的时候会报错:

 

 

 而其他类都可以正常引用,这就印证了上面所介绍的特点,如果想要引用不同包下的类,就必须使那个类的访问权限为Public。

 

三、修饰方法和变量

  修饰方法和变量的访问修饰符有四种:

  • 默认访问权限:如果一个类的方法和变量访问权限说默认的,说明在同一个包下的其他类能访问该方法或变量,而不同包下的类是不能去访问的
  • Public:被Public修饰的方法或变量,在任何地方都是可见的
  • Private:如果一个类方法或变量被Private修饰,那它在此类以外的地方都是不可见的,只允许在此类里进行访问
  • Protect:如果一个类方法和变量被Protect修饰,那它对于同一个包下的类来说都是可见的,而对于不同包的类,只有继承了该类才能访问Protect修饰的方法和变量

  具体的例子就不列举了,与上文所差不多的道理,而这里要介绍两点:

  1、对于一个.class文件,如果存在Public修饰的类,那只能有一个这样修饰的类,并且类的名字一定要与Public类的名字一样,不然会报错

  2、控制成员访问权限的意义在于:使用户不要接触到那些他们不该接触到的部分;让类库工作者能放心修改他们需要修改的地方,而不会对客户端产生重大影响

 

四、Static关键字

  一般来说,当我们创建对象的时候,具体实现类才会被分配堆空间,而当我们不想创建对象,也就是省去new的过程就想调用方法或者使用变量时,就可以利用Static关键字,而这同样与 new一个对象的初始化过程有关:这一点可以看我的另一篇文章:https://www.cnblogs.com/kxxiaomutou/p/15599901.html,这里我们主要介绍关键词Static的用处。

  在《Java编程思想》29页中有一句话:“当一个事物声明是Static时,就意味着这个域或方法不会与它的那个类的任何对象实例关联起来”,也就是说即使从未创建某个类的对象,,也可以调用其Static方法或访问其Static域。

  只要类加载了,我们就可以通过类名去访问其中的Static(静态)方法或变量,这种特性可以用来优化程序的性能,下面将从静态方法、静态变量、静态代码块三个方面介绍:

1、静态方法

  对于被Static修饰的方法来说,一般称其为静态方法,而上文说到静态方法已经与对象没有任何关系了,因此它也失去了与对象相关的东西,静态方法没有this关键字,它不能访问类中的非静态方法或者非静态变量,因为非静态方法必须依靠实例化后才能访问,而反过来倒是可行的,类中的其他方法是可以访问静态方法的,因为其不依靠任何对象,举个简单的例子:

 1 public class Publicceshi {
 2     static String x = "Staticx";
 3     String y = "y";
 4     public void print(){
 5         System.out.println(x);
 6         System.out.println(y);
 7     }
 8     static public void print1(){
 9         System.out.println(x);
10         System.out.println(y);//报错
11     }
12 }

 

  可以看到在静态方法里调用非静态的变量y出现了错误,这里我们假设如果可以调用,现在mian方法里有一句:Publicceshi.print2(),这样肯定会出现错误,因为此时的y变量都还没有,因为y的创建是需要对象的支撑,所以这样的写法肯定是错误的,这就是静态方法里只能调用静态方法或者变量的原因。

  最常见的静态方法就是main方法,因为编译器在执行mian方法时没有创建任何对象,所以main方法必须是静态的,通过类名即可访问。

  构造器是否为静态方法可以参考这篇文章:https://blog.csdn.net/qq_17864929/article/details/48006835

2、静态变量

  static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

  static成员变量的初始化顺序按照定义的顺序进行初始化。

3、静态代码块

  static关键字还有一个重要的用处,就是修饰代码块,static代码块能放在类的任何位置,同时一个类也能拥有多个静态代码块,这些代码块统一在类加载的时候被执行,并且只会执行一次。static代码块可以用来优化代码的性能,至于怎么优化性能,可以看下面这个例子:

 1 class Person{
 2     private Date birthDate;
 3      
 4     public Person(Date birthDate) {
 5         this.birthDate = birthDate;
 6     }
 7      
 8     boolean isBornBoomer() {
 9         Date startDate = Date.valueOf("1946");
10         Date endDate = Date.valueOf("1964");
11         return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
12     }
13 }

 isBornBoomer是用来这个人是否是1946-1964年出生的,而每次isBornBoomer被调用的时候,都会生成startDate和birthDate两个对象,造成了空间浪费,如果改成这样效率会更好

 

 1 class Person{
 2     private Date birthDate;
 3     private static Date startDate,endDate;
 4     static{
 5         startDate = Date.valueOf("1946");
 6         endDate = Date.valueOf("1964");
 7     }
 8      
 9     public Person(Date birthDate) {
10         this.birthDate = birthDate;
11     }
12      
13     boolean isBornBoomer() {
14         return birthDate.compareTo(startDate)>=0 && birthDate.compareTo(endDate) < 0;
15  

 

这样在类加载的时候statDate和endDate就被赋予好值了,不用每次都创建

 

4、static会改变类或者变量的访问权限吗?

  答案是不会,在C++中的特性放在Java中是不合理的,Java中的访问权限只由Public、Protect、Private这几个关键字控制

5、能通过this来访问静态成员变量吗?

  对于静态方法来说没有this,那非静态方法能通过this来调用静态成员变量吗?可以先看个例子,这段代码的输出是什么?

 1 public class Main {  
 2     static int value = 33;
 3  
 4     public static void main(String[] args) throws Exception{
 5         new Main().printValue();
 6     }
 7  
 8     private void printValue(){
 9         int value = 3;
10         System.out.println(this.value);
11     }
12 }
33
View Code

  这里面主要考察队this和static的理解。this代表什么?this代表当前对象,那么通过new Main()来调用printValue的话,当前对象就是通过new Main()生成的对象。而static变量是被对象所享有的,因此在printValue中的this.value的值毫无疑问是33。在printValue方法内部的value是局部变量,根本不可能与this关联,所以输出结果是33。在这里永远要记住一点:静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)

5、局部变量能被static修饰吗

  答案是不能,这是java的规定,至于为什么不能访问可以看这篇文章:

  http://www.debugease.com/j2se/178932.html

  

posted @ 2021-11-25 20:28  空心小木头  阅读(186)  评论(0)    收藏  举报