Java修饰符是你添加到变量、类和方法以改变其含义的关键词。它们可分为两组:html
访问控制修饰符java
非访问修饰符程序员
修饰符 说明面试
public 公共可见多线程
private 类可见ide
protected 包和全部的子类可见测试
那么如何使用这三种访问控制修饰符呢?请看下面两个类。请忽略此处代码的低效,由于这是教程。this
建立一个名为project/mypackage/Person.java文件,并添加如下代码:spa
package mypackage; class Person { private String firstname; private String lastname; protected void setFirstname(String firstname) { this.firstname = firstname; } protected void setLastname(String lastname) { this.lastname = lastname; } protected String getFirstname() { return this.firstname; } protected String getLastname() { return this.lastname; } }
上面的Person
类有private
变量和protected
方法。这意味着这些变量将只能从类访问,方法将只能从mypackage
包访问。线程
接下来建立一个名为project/mypackage/Company.java的文件,并添加如下代码:
package mypackage; import java.util.*; public class Company { private ArrayList<Person> people; public Company() { this.people = new ArrayList<Person>(); } public void addPerson(String firstname, String lastname) { Person p = new Person(); p.setFirstname(firstname); p.setLastname(lastname); this.people.add(p); } public void printPeople() { for(int i = 0; i < this.people.size(); i++) { System.out.println(this.people.get(i).getFirstname() + " " + this.people.get(i).getLastname()); } } }
上面的类是公共的,所以它能够从包内部和外部的任何类进行访问。它有一个只能在类内访问的私有变量,以及一堆的公共方法。因为Person
类和Company
类共享相同的包,因此Company
类能够访问Person
类以及全部它的方法。
为了完成访问控制修饰符的示范,让咱们在一个新的project/MainDriver.java文件中建立一个驱动程序类:
import mypackage.*; public class MainDriver { public static void main(String[] args) { Company c = new Company(); c.addPerson("Nic", "Raboy"); c.printPeople(); Person p = new Person(); p.setFirstname("Maria"); p.setLastname("Campos"); } }
请记住,因为Company
类是公共的,因此咱们在添加和打印人的时候没有问题。然而,因为Person
类是受保护的,因此咱们会获得一个编译时错误,由于MainDriver
不是mypackage
包的一部分。
如今,让咱们来看看现有的非访问修饰符,以及如何使用它们的一些示例代码。
修饰符 说明
static 用于建立类、方法和变量
final 用于最终肯定类、变量和方法的实施方式
abstract 用于建立抽象方法和类
synchronized 用于多线程的同步机制对资源进行加锁,使得在同一个时间,只有一个线程能够进行操做
Volatile 一个变量声明为volatile,就意味着这个变量是随时会被其余线程修改的,所以不能将它cache在线程memory中。
那么如何使用这五个非访问修饰符呢?
Java中static修饰符的一个很好的例子就是:
int max = Integer.MAX_VALUE
int numeric = Integer.parseInt("1234");
在上面的例子中,请注意咱们利用了Integer
类中变量和方法,而不是先实例化。这是由于那些特定的方法和变量都是静态的。
abstract修饰符则略有不一样。你能够建立一个带方法的类,但它们基本只能定义。你不能对它们添加逻辑。例如:
abstract class Shape { abstract int getArea(int width, int height); }
而后在子类里,你才能够增长例以下面这样的代码:
class Rectangle extends Shape { int getArea(int width, int height) { return width * height; } }
下面要讲讲synchronized
和volatile
修饰符。
先来看一个线程的例子,在这个例子里咱们将从两个不一样的线程去访问相同的方法:
import java.lang.*; public class ThreadExample { public static void main(String[] args) { Thread thread1 = new Thread(new Runnable() { public void run() { print("THREAD 1"); } }); Thread thread2 = new Thread(new Runnable() { public void run() { print("THREAD 2"); } }); thread1.start(); thread2.start(); } public static void print(String s) { for(int i = 0; i < 5; i++) { System.out.println(s + ": " + i); } } }
运行上述代码将输出打印一个随机的顺序。多是连续的,也可能不连续,取决于CPU。然而,若是咱们使用synchronized
修饰符,那么第一个线程必须在第二个线程开始打印以前完成。print(String s)
方法能够是这样的:
public static synchronized void print(String s) { for(int i = 0; i < 5; i++) { System.out.println(s + ": " + i); } }
接下来,让咱们看看使用volatile
修饰符的例子:
import java.lang.*; public class ThreadExample { public static volatile boolean isActive; public static void main(String[] args) { isActive = true; Thread thread1 = new Thread(new Runnable() { public void run() { while(true) { if(isActive) { System.out.println("THREAD 1"); isActive = false; } } } }); Thread thread2 = new Thread(new Runnable() { public void run() { while(true) { if(!isActive) { System.out.println("THREAD 2"); try { Thread.sleep(100); } catch (Exception e) { } isActive = true; } } } }); thread1.start(); thread2.start(); } }
因为volatile变量是一种状态标志,因此运行上面的代码会打印线程数,并在它们之间交替。这是由于该标志被存储在主存储器中。若是咱们去掉volatile
关键字,该线程将只交替一次,由于只使用一个本地参考,两个线程基本上彼此隐身。
结论
Java修饰符理解起来会有一点棘手,并且实际上不少程序员并不怎么熟悉它们。这是一个很好的面试问题,能够用于测试你的书本知识。最后,若是我有什么遗漏或解释错误的地方,欢迎各位不吝指出。