java学习笔记《java面向对象编程》——java语言中的修饰符

一、访问控制修饰符

面向对象的基本思想之一是封装实现细节并且公开接口。Java语言采用访问控制修饰符及类的方法和变量的访问权限,从而只向使用者暴露接口,但隐藏实现细节。访问控制符分4种级别。

公开级别:用public修饰,对外公开。

受保护级别:用protected修饰,向子类(可以不在一个包)及同一个包中的类公开。

默认级别:没有访问控制修饰符,向同一个包中的类公开。

私有级别:用private修饰,只有类本身可以访问,不对外公开。

成员变量、成员方法和构造方法可以处于4个访问级别中的一个:公开、受保护、默认或私有。顶层类只可以处于默认或公开访问级别,因此顶层类不能用private和protected来修饰。(和顶层类对应的呢?底层类可以被private和protected修饰?)

值得注意的是,访问级别仅仅适用于类及类的成员,而不适用于局部变量。局部变量只能在方法内部别访问,不能用public、protected和private来修饰。

在一个类中,可以访问类本身或内部类的实例的私有成员。

class A{
	private int v;
	class B{
		private int v;
		class C{
			private int v;
		}
	}
	void test(){
		A a=new A();
		a.v=1;
		B b=new B();
		b.v=1;
		B.C c=new B().new C();//?????????
		c.v=1;
	}
}
这里内部类还不是很了解,等后面在解释一下这种现象,这里只需要明白可以访问内部类的私有成员即可。

二、abstract修饰符

abstract修饰符可以用来修饰类和方法。

使用abstract修饰符需要遵守一下语法规则:

(1)抽象类中可以没有抽象方法,但包含了抽象方法的类必须被定义为抽象类。如果子类没有实现父类中所有的抽象方法,那么子类也必须被定义为抽象类,否则编译出错。

(2)没有抽象构造方法,也没有抽象静态方法。抽象类中可以有静态方法。

(3)抽象类中可以有非抽象的构造方法,创建子类的实例时可能会调用这些构造方法。抽象类不能被实例化,然而可以创建一个引用变量,其类型是一个抽象类,并让它引用非抽象类的子类的一个实例。

(4)抽象类及抽象方法不能被final修饰符修饰。abstract修饰符与final修饰符不能连用。因为抽象类只有允许创建其子类,它的抽象方法才能被实现并且只有它的具体子类才能被实例化,而用final修饰的类不允许拥有子类,用final修饰的方法不允许被子类覆盖,因此把abstract修饰符与final修饰符连用,会导致自相矛盾。

三、final修饰符

final具有“不可改变的”含义,它可以修饰非抽象类、非抽象成员方法和变量。

(1)用final修饰的类不能被继承,没有子类。

(2)用final修饰的方法不能被子类的方法覆盖。

(3)用final修饰的变量表示常量,只能被赋值一次。

final不能用来修饰构造方法,因为“方法覆盖”这一概念仅适用于类的成员方法,而不适用于类的构造方法,父类的构造方法和子类的构造方法之间不存在覆盖关系,因此用final修饰构造方法是无意义的。父类中用private修饰的方法不能被子类的方法覆盖,因此private类型的方法默认是final类型的。

这样看来,构造方法是不能被abstract、static、final修饰的,虽然private类型的方法默认都是final类型的,但是可以被private修饰符修饰,在构造方法这里比较特殊。

1、final类

继承关系的弱点是打破封装,子类能够访问父类的实现细节,而且能以方法覆盖的方式修改实现细节。在以下情况下,可以考虑把类定义为final类型,使得这个类不能被继承。

(1)不是专门为继承而设计的类,类本身的方法之间有复杂的调用关系。假如随意创建这些类的子类,子类有可能会错误的修改父类的实现细节。

(2)出于安全的原因,类的实现细节不允许有任何改动。

(3)在创建对象模型时,确信这个类不会再被扩展。

2、final方法

在某些情况下,出于安全的原因,父类不允许子类覆盖某个方法,此时可以把这个方法声明为final类型。private类型的方法都默认为是final方法,因而不能被子类的方法覆盖。

3、final变量

用final修饰的变量表示取值不会改变的常量。

final变量具有一下特征:

(1)final修饰符可以修饰静态变量、实例变量和局部变量,分别表示静态常量、实例常量和局部常量。

(2)final类型的成员变量都必须显示初始化,否则会导致编译出错。对于final类型的实例变量,可以在定义变量时,或者在构造方法中进行初始化;对于final类型的静态变量,只能在定义变量时进行初始化。

(3)final变量只能赋值一次,意味着一旦final被显示初始化之后就不能再改变数值了。

(4)如果将引用类型的变量用final修饰,那么该变量只能始终引用一个对象,但可以改变对象的内容。

在程序中通过final修饰符来定义常量,具有以下作用:

(1)提高程序的安全性,禁止非法修改取之固定并且不允许改变的数据。

(2)提高程序代码的可维护性(这就是是把具体数据变成常量变量的好处)。

(3)提高程序代码的可读性。

四、static修饰符

static修饰符可以用来修饰类的成员变量、成员方法和代码块。

(1)用static修饰的成员变量表示静态变量,可以直接通过类名来访问。

(2)用static修饰的成员方法表示静态方法,可以直接通过类名来访问。

(3)用static修饰的程序代码块表示静态代码块,当Java虚拟机加载类的时候,就会执行该代码。

被static修饰的成员变量和成员方法表明归某个类所有,它不依赖于类的特定实例,被类的所有实例共享。只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定位到它们。

1、static变量

类的成员变量有两种:一种是被static修饰的变量,叫类变量或静态变量;另一种是没有被static修饰的变量,叫实例变量。

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

(1)静态变量在内存中只有一个拷贝,运行时Java虚拟机只为静态变量分配一次内存,在加载类的过程中完成静态变量的内存分配。可以直接通过类名访问静态变量。

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

在类的内部,可以在任何方法内直接访问静态变量;在其他类中,可以通过某个类的类名来访问它的静态变量。

static变量在某种程度上与其他语言(如C语言)中的全局变量相似。Java语言不支持不属于任何类的全局变量,静态变量提供了这一功能,它有如下两个作用。

(1)能被类的所有实例共享,可作为实例之间进行交流的共享数据。

(2)如果类的所有实例都包含一个相同的常量属性,可把这个属性定义为静态常量类型,从而节省内存空间。

2、static方法

成员方法分为静态方法和实例方法。用static修饰的方法叫静态方法,或类方法。静态方法也和静态变量一样,不需要创建类的实例,可以直接通过类名来访问。

(1)静态方法可访问的内容

因为静态方法不需要通过它所属的类的任何实例就会被调用,因此在静态方法中不能使用this关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法。同样的,super关键字与类的特定实例相关,静态方法中也不能使用super关键字。

(2)实例方法可访问的内容

如果一个方法没有用static修饰,那么它就是实例方法。在实例方法中可以直接访问所属类的静态变量、静态方法、实例变量和实例方法。

(3)静态方法必须被实现

静态方法用来表示某个类所特有的功能,这种功能的实现不依赖于类的具体实例,也不依赖于它的子类。既然如此,当前类必须为静态方法提供实现。换句话说,一个静态的方法不能被定义为抽象方法。static和abstract修饰符不可以一起使用。如果一个方法是静态的,它就必须自己实现该方法;如果一个方法是抽象的,那么它就只表示所具有的功能,但不会实现它,在子类中才会实现它。

(4)作为程序入口的main()方法是静态方法

把main()方法定义为静态方法,就可以使得Java虚拟机只要加载了main()方法所属的类,就能执行main()方法,而无须先创建这个类的实例。

在main()静态方法中不能直接访问实例变量和实例方法。正确的做法是:通过类的实例的引用来访问实例方法和实例变量,在其他的静态方法中,也可以先创建某个类的实例,再用这个类的实例来调用这个类的实例方法和实例变量。

(5)方法的字节码都位于方法区

不管实例方法,还是静态方法,它们的字节码都位于方法区内。Java编译器把Java方法的源程序代码编译成二进制的编码,称为字节码。Java虚拟机的解析器能够解析这种字节码。方法的字节码都在方法区。

3、static代码块

类中可以包含静态代码块,它不存在于任何方法体中。在Java虚拟机加载类时会执行这些静态代码块。如果类中包含多个静态代码块,那么Java虚拟机将按照它们在类中出现的顺序依次执行它们,每个静态代码块就会被执行一次。

类的构造方法用于初始化类的实例,而类的静态代码块则用于初始化类,给类的静态变量赋初值。

静态代码块和静态方法一样,也不能直接访问类的实例变量和实例方法,而必须通过实例的引用来访问它们。

4、小结

抽象类不能被定义为private、final和static类型。没有抽象构造方法。

private类型的方法都默认为是final方法,因而不能被子类的方法覆盖。

许多修饰符可以连用,例如:

private static final int MAX_COUNT=1;

public static final void main(String args[]){....}

protected abstract void method();

许多个修饰符连用时,修饰符的顺序可以颠倒,例如以下3种方式定义都是合法的:

private static final int MAX_COUNT=1;

static private final int MAX_COUNT=1;

final static private int MAX_COUNT=1;

不过作为普遍遵循的编程规范,通常把访问控制符放在首位,其次是static或abstract修饰符,接着是其他修饰符。

以下修饰符连用是无意义的,会导致编译错误:

abstract与private

abstract与final

abstract与static

这样看来,修饰符不能连用的情况都涉及到了abstract,其他的修饰符之间可以连用。

你可能感兴趣的:(before)