JAVA-(访问级别修饰符+static)的理解

访问级别修饰符

访问级别

访问级别修饰符确定其他类是否可以使用特定字段或调用特定方法。有两个级别的访问控制:

  1. 在顶级
  • public或package-private(没有显式修饰符即默认权限)。
    类可以用修饰符public声明,在这种情况下,类对所有类都可见。如果一个类没有修饰符(默认,也称为package-private),它只在自己的包中可见。
  1. 在成员级别

public,private,protected或package-private(没有显式修饰符即默认权限)。
在成员级别,也可以使用public修饰符或无修饰符(package-private),如同顶级类一样,具有相同的含义。
对于成员,除public和默认外有两个附加的访问修饰符:private和protected:

  • private修饰符指定该成员只能在其自己的类中访问。
  • protected修饰符指定该成员只能在其自己的包(如package-private)中访问,此外还可以由另一个包中的该类的子类访问。
作用域当前类同一package子孙类其他package
public
protected×
friendly××
private×××

不写时默认为friendly。
第一列指示类本身是否有权访问由访问级别定义的成员。正如你可以看到,一个类总是有权访问它自己的成员。
第二列指示与该类(不管其父级)相同的包中的类是否具有对成员的访问权限。
第三列指示在此包外部声明的该类的子类是否有权访问成员。
第四列指示此包外部是否所有类都具有对成员的访问权限。

选择访问级别的提示:

如果其他程序员使用你的类,你想要确保不会发生滥用错误。访问级别可以帮助您这样做。

  1. 使用对特定成员有意义的最严格的访问级别。使用私人,除非你有一个很好的理由不使用。
  2. 避免使用公共字段(常量除外)。公共字段往往会将您链接到特定实现
    并限制您在更改代码时的灵活性。

验证成员函数

  • Alpha和Beta在同一个package下:
package com.one;     
public class Alpha{

	public void test(){
		this.pub();
		this.pro();
		this.def();
		this.pri();
	}     
	public void pub(){
	System.out.println( "public");
	}     
	protected void pro(){
		System.out.println( "protected");
	}    	
	void def(){
		System.out.println( "default");
	}     
	private void pri(){
		System.out.println( "private");
	}
}
  • Beta类
package com.one;
    
public class Beta{
	public void test(){
		Alpha alpha = new Alpha();
		alpha.pub();
		alpha.pro();
		alpha.def();
		alpha.pri();
	}     
}
  • AlphaSub作为Alpha的子类,用super进行验证。AlphaSub与Alpha不在同一个packa下。
package com.two;
import com.one.Alpha;

public class AlphaSub extends Alpha{
	public void test(){
		super.pub();
		super.pro();
		super.def();
		super.pri();
	}
}
  • Gamma与Alpha不同包且无继承关系
package com.two;
import com.one.Alpha;
 
public class Gamma{
	public void test(){
		Alpha alpha = new Alpha();
		alpha.pub();
		alpha.pro();
		alpha.def();
		alpha.pri();
	}
}

  • 验证Alpha类
import com.one.Alpha;
 
class  Test {
	public static void main(String[] args) {
		new Alpha().test();
	}
}
//分别编译Alpha.java和Test.java: 
F:\javaStuff>javac -d F:\javaStuff Alpha.java
F:\javaStuff>javac Test.java
F:\javaStuff>java Test
public
protected
default
private
//编译没有报错,即证明四种访问权限在类内都是可以访问的 
  • 验证Beta类
//依次编译Alpha.java和Beta.java
F:\javaStuff>javac -d F:\javaStuff Alpha.java
F:\javaStuff>javac -d F:\javaStuff Beta.java
Beta.java:11: 错误: pri()可以在Alpha中访问private
                alpha.pri();
                     ^
1 个错误
//编译Beta.java时报错,提示Alpha类中的pro方法是私有的,不可访问
  • 验证AlphaSub类
//依次编译Alpha.java和AlphaSub.java
F:\javaStuff>javac -d F:\javaStuff Alpha.java 
F:\javaStuff>javac -d F:\javaStuff AlphaSub.java
AlphaSub.java:10: 错误: def()在Alpha中不是公共的; 无法从外部程序包中对其进行访问
                super.def();
                     ^
AlphaSub.java:11: 错误: pri()可以在Alpha中访问private
                super.pri();
                     ^
2 个错误
//Alpha的def方法为默认权限无法在外部包访问
//Alpha的pri方法为私有权限无法在外部包访问
  • 验证Gamma类
//依次编译Alpha.java和Gamma.java
F:\javaStuff>javac -d F:\javaStuff Alpha.java
F:\javaStuff>javac -d F:\javaStuff Gamma.java
Gamma.java:10: 错误: pro()可以在Alpha中访问protected
                alpha.pro();
                     ^
Gamma.java:11: 错误: def()在Alpha中不是公共的; 无法从外部程序包中对其进行访问
                alpha.def();
                     ^
Gamma.java:12: 错误: pri()可以在Alpha中访问private
                alpha.pri();
                     ^
3 个错误
//Alpha的def方法为默认权限无法在外部包访问
//Alpha的pri方法为私有权限无法在外部包访问
//Alpha的pro方法为保护方法无法被外部非子类访问

代码结构目录:

因为编译Beta、AlphaSub和Gamma时都有编译错误自然就不会生成com.two包了
代码结构目录

Static

(概念)static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念。
(概念)用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象时,不生成static变量的副本,而是类的所有实例共享同一个static变量。
(概念)只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内找到他们。因此,static对象可以在它的任何对象创建之前访问,无需引用任何对象。

静态方法的调用:

静态方法可以直接通过类名调用,任何的实例也都可以调用静态方法。前面的代码中有直接通过类名调用的例子


静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和成员方法。因为实例成员与特定的对象关联!


因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
静态方法是类内部的一类特殊方法,只有在需要时才将对应的方法声明成静态的,一个类内部的方法一般都是非静态的

声明为static的变量实质上就是全局变量。当声明一个对象时,并不产生static变量的拷贝,而是该类所有的实例变量共用同一个static变量。声明为static的方法有以下几条限制:

  • 它们仅能调用其他的static 方法。
  • 它们只能访问static数据。
  • 它们不能以任何方式引用this 或super(关键字super 与继承有关)。
    如果你需要通过计算来初始化你的static变量,你可以声明一个static块,Static 块仅在该类被加载时执行一次。
  • 注意:在一个static 方法中引用任何实例变量都是非法的。

用public修饰的static成员变量和成员方法本质是全局变量和全局方法,当声明它类的对象市,不生成static变量的副本,而是类的所有实例共享同一个static变量。代码验证:

  • Demo1
public class Demo1 {
    public static int i = 1;
    public int j = 2;
    
    public static int getNumber(){
        return i;
		//这个return返回的是全局变量的i,即前面创建的i
    }
    
    public int getDealNumber(int j){
        return j;
		//这个return返回的是所传进来的参数,是(int j)这个东西
    }

}
  • Demo2
public class Demo2 {
    public static void main(String args[]){
		//想要使用Demo1中的静态的(即全局的)变量i,直接用类名引用就可以了
        int i = Demo1.i;
		//但是想要得到Demo1中的实例的变量j(非静态变量),我需要怎么做呢?(此刻牢记java面向对象的思想!)
		//首先我要先new一个Demo1的对象,然后才可以通过new出来的对象得到Demo1中的j(这个过程叫做构造实例化)
		//Demo1():是构造容器,Demo1:是类名,demo1:是对象名
        Demo1 demo1 = new Demo1();
        int j = demo1.j;
		//同理,java中的static方法和非static方法都是一样的区别
		//getNumber方法是静态的,可以直接根据类名调用方法
        int ii = Demo1.getNumber();
		//getDealNumber是非静态的,需要使用调用实例的方法,利用前面所new出来的Demo1的对象demo1通过“.”来调用方法
        int jj = demo1.getDealNumber(1);
    }
}

静态变量和实例变量的区别:

两者的区别是:

静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,可用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。


实例变量,没创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。


使用静态变量的环境:

  1. 在对象之间共享值时
  2. 方便访问变量时

有时你希望定义一个类成员,使它的使用完全独立于该类的任何对象。通常情况下,类成员必须通过它的类的对象访问,但是可以创建这样一个成员,它能够被它自己使用,而不必引用特定的实例。在成员的声明前面加上关键字static(静态的)就能创建这样的成员。如果一个成员被声明为static,它就能够在它的类的任何对象创建之前被访问,而不必引用任何对象。你可以将方法和变量都声明为static。static 成员的最常见的例子是main( ) 。因为在程序开始执行时必须调用main() ,所以它被声明为static。

static代码块

static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块.
如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。例如:

public class Test5 {
	private static int a;
	private int b;

	static{
		Test5.a=3;
		System.out.println(a);
		//构造实例化
		Test5 t=new Test5();
		//调用Test5下的方法fax
		t.fax();
		t.b=1000;
		System.out.println(t.b);
	}
	
	static{
		Test5.a=4;
		System.out.println(a);
		}
	
	// TODO 自动生成方法存根
	public static void main(String[] args) {
	}

	static{
		Test5.a=5;
		System.out.println(a);
	}

	//创建公有的实例化变量fax
	public void fax(){
		System.out.println("hhahhahah");
	}
}  


运行结果:
3
hhahhahah
1000
4
5

利用静态代码块可以对一些static变量进行赋值,就一个static的main方法,这样JVM在运行main方法的时候可以直接调用而不用创建实例。

static 块初始化:

class UseStatic {
	static int a = 3;
	static int b;

	static void meth(int x) {
		System.out.println("x = " + x);
		System.out.println("a = " + a);
		System.out.println("b = " + b);
	}

	static {
		System.out.println("Static block initialized.");
		b = a * 4;
	}

	public static void main(String args[]) {
		meth(42);
	}
} 

一旦UseStatic 类被装载,所有的static语句被运行。首先,a被设置为3,接着static 块执行(打印一条消息),最后,b被初始化为a*4 或12。然后调用main(),main() 调用meth() ,把值42传递给x。3个println ( ) 语句引用两个static变量a和b,以及局部变量x 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值