方法详解
方法的所属性
java语言是静态的,一个类定义完成后,只要不再重新编译这个类文件,该类和该类的对象所拥有的方法是固定的,永远都不会该变。
同一个类的一个方法调用另外一个方法时,如果被调方法是普通方法,则默认使用this作为调用者;如果被调方法是时静态方法,则默认使用类作为调用者。
java里方法的所属性主要体现在一下几个方面:
1.方法不能独立定义,方法只能在类体里定义。
2.从逻辑意义上来看,方法要么属于该类本身,要么属于该类的一个对象。
3.永远不能独立执行方法,执行方法必须使用类或对象作为调用者。
PS:使用static修饰的方法属于这个类本身,既可以使用类作为调用者也可以使用对象作为调用者。
没有static修饰的方法属于该类的对象,只能使用对象作为调用者来调用。
方法的参数传递机制
java里方法的参数传递方式只有一种:值传递
所谓值传递,就是将实参数值的副本传入方法内,而参数本身不会受到任何影响。
1.基本类型参数传递
public class PrimitiveTransferTest {
public static void swap(int a,int b){
int tmp = a;
a = b;
b = tmp;
System.out.println("swap方法里,a的值是"+a+"b的值是:"+b);
}
public static void main(String[] args){
int a = 6;
int b = 9;
swap(a, b);
System.out.println("交换结束后,a的值是"+a+"b的值是:"+b);
}
}
main()方法中的变量作为参数值传入swap()方法存储示意图
交换之后的存储示意图如下:
在main()方法中调用swap()方法时,main()方法还未结束,因此系统分别为main()方法和swap()方法分配两块栈区,用于保存main()方法和swap()方法的局部变量。main()方法中的两个变量作为参数传入swap()方法,实际上实在swap()方法栈区中重新产生了两个变量,并将main()中的值赋给swap()方法栈区中的参数(就是对swap()方法的形参进行初始化),此时系统存在两个a变量,两个b变量,只是存在于不同的方法栈区中而已。
如上图方法里操作的并不是实际的实参变量。
2.引用类型参数传递
引用类型参数传递一样是值传递方式。
class DataWrap {
int a;
int b;
}
public class ReferenceTransferTest {
public static void swap(DataWrap dw){
int tmp = dw.a;
dw.a = dw.b;
dw.b = tmp;
System.out.println("swap方法里,a的值是"+dw.a+"b的值是:"+dw.b);
}
public static void main(String[] args){
DataWrap dw = new DataWrap();
dw.a = 6;
dw.b = 9;
swap(dw);
System.out.println("交换结束后,a的值是"+dw.a+"b的值是:"+dw.b);
}
}
main()方法中的dw传入swap()方法后的存储示意图
将swap()方法的dw赋值为null后存储示意图如下:
引用类型的参数传递时传递的是地址,所以修改的是同一个对象。
形参个数可变的方法
public class Varargs {
public static void test(int a ,String ...books){
for(String tmp : books){
System.out.println(tmp);
}
System.out.println(a);
}
public static void main(String[] args){
test(5,"java讲义","轻量级java EE");
}
}
运行结果如下:
从结果可以看出,当调用test()方法是,books参数可以传入多个字符串作为参数值。形参个数可变的参数本质就是一个数组参数。也可以用一下这种方式使用,但是较为麻烦。
public static void test(int a, String[] books);
调用时需要传入一个数组:方式如下
test(23,new String["fengkaugn "]);
个数可变的形参只能处于形参列表的最后,也就是说,一个方法中最多只能有一个数可变的形参。
方法重载
java允许同一个类里定义多个同名方法,只要形参列表不同就行。这种形式叫做方法重载。
成员变量和局部变量
成员变量和局部变量
成员变量指的是在类里定义的变量,局部变量指的是在方法里定义的变量。
局部变量分为以下三种:
形参:在定义方法签名时定义的变量,形参的作用域在整个方法内有效。
方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量的地方生效,到该方法结束时失效。
代码块局部变量:在代码块中定义的局部变量,这个局部变量的作用域从定义该变量的地方生效,到该代码块结束时失效。
局部变量除形参之外,都必须显示初始化,否则不可以访问它们。
成员变量无需显示初始化,只要为一个类定义了类变量或实例变量,系统就会在这个类的准备阶段或创建该类的实例时进行默认初始化,与数组动态初始化时元素的默认赋值规则相同。
类变量的作用于比实例变量的作用域更大,随类的存在而存在。
不同类型下系统给定的默认值:
整数类型(byte、short、int、long)初值为0
浮点类型(float、double)初值为0.0
字符类型(char)初值为’u\0000’
布尔类型(boolean)初值为false
引用类型(类、接口和数组)初值为null
成员变量的初始化和内存中的运行机制
第一次使用类时加载这个类并进行初始化。在类的准备阶段,系统为该类的类变量分配内存空间,并制定默认初始值。当类初始化完成后,系统将在堆内存中为该类分配一块内存区,该内存区里包含保存类变量的内存,并设初值。
实例变量实在创建实例时分配内存空间并制定初始值的。
局部变量的初始化和内存中的运行机制
局部变量不属于任何类或实例,因此它总是保存在其所在方法的栈内存中。
如果局部变量是基本类型的变量,则直接把这个变量的值保存在该变量对应的内存中;如果局部变量是一个引用类型的变量,则这个变量里存放的是地址,通过改地址引用到改变来那个实际引用的对象或数组。
问题:任何情况都是用成员变量的缺点?
答:1.增大了变量的生存时间,导致更大的内存开销
2.扩大了变量的作用域,不利于提高程序的内聚性