对象值的传递
Java 中没有指针。所有也没有引用传递,仅仅有值传递。不过可以通过对象的方式来引用传递。
值传递
方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参数的值。传递值的数据类型主要是基本数据类型,包括整型,浮点型。
public class Test {
public static void change(int i, int j){
//定义一个静态方法change,该方法有两个参数 i 和 j。
int temp = i;
i = j;
j = temp;
}
public static void main(String[] args){
int a = 3;
int b = 4;
change(a, b);
System.out.println("a = " + a);
System.out.println("b = " + b);
}
}
由此可以确定 ,传递的值不会改变原值。
引用传递
方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中对应的形式的参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数值。
传递地址值的数据类型为除String以外的所有复合数据类型,包括数组、类和接口。
class A { //定义一个类
int i = 0;
}
public class Test {
public static void add(A a) {
//a = new A(); //没有注释,值为 1
a.i++;
}
public static void main(String args[]){
A a = new A();
add(a);
System.out.println(a.i); // 值为 0
}
}
// 因为 a = new A();构造了新的A对象,不是传递的那个对象。
作用域修饰符
主要分为访问修饰符和非访问修饰符。修饰符用来定义类、方法或者变量,通常放在语句最前面。
访问修饰符
可以使用访问修饰符来规定对类、变量、方法和构造方法的访问。Java 提供了四种不同的访问权限,以实现不同范围的访问能力。
private(私有的)
对应最严格的访问级别,主要用来隐藏类的实现细节和保护类的数据。方法、变量和构造方法只能被所属类访问,并且类和接口不能被声明为private。
声明为 private 的变量只能通过类中的公共方法被外部类访问。
public class PrivateTest {
private String name; //私有的成员变量
public String getName(){ //私有成员变量的get方法
return name;
}
public void setName(String name){ //私有成员变量的set方法
this.name = name;
}
public static void main(String[] args){
PrivateTest p = new PrivateTest(); //创建类的对象
p.setName("private 访问修饰符"); //调用对象的 set 方法,为成员变量赋值
System.out.println("name = " + p.getName());//打印成员变量 name 的值
}
}
无访问修饰符
不使用访问修饰符声明的变量和方法,可以被这个类本身或者与类在同一个包内的其他类访问。
接口中的变量都隐式声明为 public static final,而接口中的方法默认情况下访问权限为 public ,因此无访问修饰符也成为默认访问修饰符
public class DefaultTest{
String name; //设置默认访问修饰符的成员变量
String getName(){ //默认访问修饰符成员变量的 get 方法
return name;
}
void setName(String name){ //默认访问修饰符成员变量的 set 方法
this.name = name;
}
public static void main(String[] args){
DefaultTest d = new DefaultTest();
d.setName("Default test");
System.out.println(d.getName());
}
}
// 他们可以被房前类或者与类在同一个包中的其他类访问。
protected(受保护的)
不能修饰类和接口。可以方法和成员变量,但是接口的成员变量和成员方法不能为protected。
package create; //create 包
public class Person { //父类
protected String name;
protected void sing(){ //用protected修饰的方法
System.out.println("父类....");
}
}
package child; //与父类不在一个包中
import create.Person; //引入父类
public class Woman extends Person{ //继承父类的子类
public static void main(String[] args){
Woman w = new Woman();
w.sing(); //调用子类在父类继承的方法
w.name = "protected";
System.out.println(w.name);
}
}
// 如果把 sing() 方法声明为 private ,那么除了父类 Person 之外的类将不能访问该方法。如果把sing() 方法声明为public,那么所有的类都能访问该方法。如果不给sing()方法加访问修饰符,那么只有在同一个包中的类才能访问它。
public(公有的)
类、方法、构造方法和接口能够被任何其他类访问。如果几个相互访问的public类分布在不同的包中,则需要使用关键字 import 导入相应的 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
非访问修饰符
如:static、final、abstract、synchronized、transient 和 volatile....
static
用来修饰类的成员变量和成员方法,一般成为静态变量和静态方法,可以通过类名访问;也可以形成静态代码块。语法格式【 类名.静态方法名( 参数列表 );类名.静态变量名; 】
- 静态变量
- 静态变量也被成为类变量。局部变量不能被声明static变量。
- 独立于该类的任何对象,被类的所有对象共享。
- 无论一个类实例化多少对象,它的静态变量都只有一份。因此,static对象可以在它的任何对象创建之前访问,无须引用任何对象。
- 静态方法
- static用来声明独立于对象的静态方法,不能使用类的非静态变量。
- 因为static修饰的方法独立于任何对象,因此static方法必须被实现,而不能是抽象的abstract。
- 静态方法直接通过类名调用,任何对象也都可以调用它,因此静态方法中不能用 this 和 super 关键字,不能直接访问所属类的成员变量和成员方法,只能访问所属类的静态变量和静态成员方法。
- static 代码块
- 也称静态代码块,实在类中独立于类成员的static语句块,可以有多个,位置随便放,不在任何方法体内。
- 用 static 和 final 修饰的成员变量一旦初始化,它的值就不可以修改,并且要通过类名访问,它的名称一般建议使用大写字母。
- 用 static 和 final 修饰的成员方法不可以被重写,并且直接通过类名访问。
-
public class StaticTest { public static final String BANANA = "香蕉"; //static final 修饰的常量 public static float price = 5.2f; //final 定义的成员变量 static{ System.out.println("static 静态块"); // 在类加载时执行 } public static void test(){ System.out.println(StaticTest.BANANA + "的价格是:" + StaticTest.price); } public static void main(String[] args){ StaticTest st = new StaticTest(); // 创建类的对象 st st.test(); // 通过对象 st 调用 test() System.out.println("main()中,"+st.BANANA + "的price = " + st.price); // 通过对象 st 调用类的静态成员变量和常量打印输出他们的值。 } }
final
可以修饰类、方法和变量,意义不同,本质相同,都表示不可改变。
- final 的变量
- 用 final 修饰的成员变量表示常量,值一旦给定就无法改变。
- 修饰的变量通常有 3 种,静态变量、成员变量、局部变量。
- 变量的初始化可以在两个地方,一是在定义时初始化,二是在构造函数中赋值。
- 允许先声明不给初值(final 空白)
- final 的方法
- 如果一个类不允许其子类覆盖某个方法,可以把这个方法声明为 final 方法。
- 两个原因:一、把方法锁定,防止任何继承类修改它的意义和实现;二、高效。编译器在遇到调用final方法时,会转入内嵌机制,大大提高执行效率。
- 类的成员方法使用final修饰,方法能被重写
-
[修饰符] final 返回值类型 方法名 ([参数类型 参数,......]){ 方法体 }
final 的声明方法
- final 修饰类
final class 类名{ 类体 }
- 用 final 声明的类不能被继承,即最终类。因此 final类的成员方法没有机会被覆盖,默认都是 final 的。
- 设计类的时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会被扩展,那么就设置为 final 类。
- 格式
- final 关键字的使用
-
public class Father{ //定义父类 final int f = 9; final void work(){ System.out.println("我在上课....."); } } public class Son extends Father{ public static void main(String[] args){ Son s = new Son(); s.f = 12; //错误:无法为最终变量f分配值 System.out.println(s.f); } void work(){ // 子类尝试重写父类的work() } //Son中的work()无法覆盖Father中的work(),被覆盖的方法为final }
-
abstract
用来修饰抽象类。不能用来实例化对象,只有抽象类的非抽象子类可以创建对象。声明抽象类的唯一目的是为了将来对该类进行扩充。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
抽象类可以包含抽象方法和非抽象方法。如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类不可以包含抽象方法。抽象方法的声明以分号结尾。
抽象方法不能被声明为 final 和 static。
抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。
声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
class abstract A {
}
class B extends A{
//Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
public abstract double computePay(); //抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
}
public static void main(String[] args){
//下面这行会造成编译不通过
A a=new A();
//可以
B b = new B();
}
synchronized修饰符
声明的方法同一时间只能被一个线程访问。
在某个范围内,synchronized 修饰的方法可以防止多个线程同时访问。不同对象的synchronized方法是不相干扰的,即其他线程照样可以同时访问相同类的另一个对象中的synchronized方法。