成员变量和成员方法的使用:
1、在其他类中
(1)成员变量
①静态
类名.静态变量
对象名.静态变量
匿名对象.静态变量
②非静态
对象名.实例变量
匿名对象.实例变量
(2)成员方法
①静态
类名.静态方法(【实参列表】)
对象名.静态方法(【实参列表】)
匿名对象.静态方法(【实参列表】)
②非静态
对象名.实例方法(【实参列表】)
匿名对象.实例方法(【实参列表】)
2、在本类中
(1)成员变量
①静态
静态的方法中,可以直接使用本类的静态变量
非静态的方法中,可以直接使用本类的静态变量
②非静态
在本类的静态方法中,无法直接使用本类的非静态的成员变量
在本类的非静态方法中,可以直接使用本类的非静态的成员变量
(2)成员方法
①静态
静态的方法中,可以直接调用本类的静态方法
非静态的方法中,可以直接调用本类的静态方法
②非静态
在本类中的静态方法中,无法直接调用本类的非静态的成员方法
在本类的非静态方法中,可以直接调用本类的非静态的成员方法
结论:
在静态方法中,无法直接使用本类的非静态的成员变量和成员方法
静态 用 静态 可以
静态 用 非静态 不行
非静态 用 静态 可以
非静态 用 非静态 可以
class FieldMethodUse{
int a;
static int b;
public static void main(String[] args){
//System.out.println("a = " + a);//错误: 无法从静态上下文中引用非静态 变量 a
//System.out.println("b = " + b);//静态方法中,直接访问本类的静态变量 OK
//test();//错误: 无法从静态上下文中引用非静态 方法 test() NO
//method();//静态方法中,直接访问本类的静态方法 OK
Circle c = new Circle();
c.radius = 1.2;
//String info = c.getInfo();
//System.out.println(info);
System.out.println(c.getInfo());
}
public void test(){
System.out.println("a = " + a);//非静态方法,直接访问本类的非静态变量 OK
System.out.println("b = " + b);//非静态方法,直接访问本类的静态变量 OK
}
public void fun(){
test();//非静态方法,直接访问本类的非静态方法 OK
method();//非静态方法,直接访问本类的静态方法 OK
}
public static void method(){
}
}
class Circle{
static String name = "圆";
double radius;
//声明一个求面积的方法
/*
修饰符:要不要静态?
如果是静态的,就是所有对象相同,面积,每一个圆对象不同,所以不同用静态的
返回值类型:需要返回面积的值,double
方法名:getArea
(形参列表):是否需要调用者给你传递参数,这个参数是用于完成方法的功能,不需要
功能:求面积
*/
double getArea(){
return Math.PI * radius * radius;
}
//声明一个方法,可以返回圆的信息
//例如:图形名:xx,半径:xx,面积:xx
/*
修饰符:要不要静态?
每一个圆的信息不同,不能用静态的
返回值类型:拼接结果,String
方法名:getInfo
(形参列表):是否需要调用者给你传递参数,这个参数是用于完成方法的功能,不需要
*/
String getInfo(){
return "图形名:" + name + ",半径:" + radius + ",面积:"+ getArea();
}
}
一、方法调用的内存分析(理解)
方法不调用不执行,调用一次执行一次,
每次调用会在栈中有一个入栈动作,
即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值等,
当方法执行结束后,会释放该内存,称为出栈,
如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,
回到调用处继续执行下一条指令。
class MethodInvoke{
public static void main(String[] args){
System.out.println(max(3,5));
System.out.println(max(4,3));
}
public static int max(int a, int b){
return a > b ? a : b;
}
}
二、方法的参数传递机制(理解,重要,会分析,会做面试题)
1、分清楚参数:
形参:声明方法的()
实参:调用方法的()
2、 分清楚谁给谁传值:实参给形参传值
3、传的是什么值?
(1)形参是基本数据类型,实参给形参的是数据的值,
然后形参的修改,和实参无关
class PassParamValue{
public static void main(String[] args){
int num = 1;
change(num);
System.out.println("num = " + num);//num= 1
}
public static void change(int a){
a = 2 * a;//形参a的值修改了,和num实参无关
}
}
(2)形参是引用数据类型,实参给形参的是地址值,
然后形参通过这个地址,修改了这个对象在堆中成员变量/元素的值,或者在方法区的静态变量的值,
都会影响实参。
因为此时形参和实参指向了同一个堆中的对象。
class PassParamValue2{
public static void main(String[] args){
MyData m = new MyData();
m.x = 1;
change(m);
System.out.println(m.x);//2
}
public static void change(MyData my){//形参是引用数据类型
my.x = 2 * my.x;
}
}
class MyData{
int x;
}
面试题:
希望打印结果:
x = 2;
y = 1;
public class PassParamExer2{
public static void main(String[] args){
int x = 1;
int y = 2;
method(x,y);
System.out.println("x = " + x);
System.out.println("y = " + y);
}
//请编码method()方法的代码,实现上面的效果
public static void method(int x, int y){
int temp = x;
x = y;
y = temp;
System.out.println("x = " + x);
System.out.println("y = " + y);
System.exit(0);//退出JVM,结束程序的运行,使得main中的两个打印语句不执行
}
/*
//失败
public static void method(int x, int y){
int temp = x;
x = y;
y = temp;
}
*/
}
方法参数传递的机制:值传递
(1)形参是基本数据类型:
实参给形参传递的是数据值,形参的修改不影响实参
(2)形参是引用数据类型:
实参给形参传递的是地址值,形参通过这个地址值修改了堆中对象的成员变量/元素的值,影响实参。
关于引用数据类型,问题/陷阱:
(1)形参 = new 类名();
即形参指向了新的对象,和实参就无关了
class PassParamProblem1{
public static void main(String[] args){
MyData m = new MyData();
m.x = 1;
change(m);
System.out.println("m.x = " + m.x);//1
}
public static void change(MyData my){//形参是引用数据类型
my = new MyData();
my.x = 2 * my.x;
}
}
class MyData{
int x;
}
(2)形参是String、Integer等类型时,
无论形参怎么修改都和实参无关。
因为String、Integer等类型是不可变对象类型,只要修改就会产生新对象。
class PassParamProblem2{
public static void main(String[] args){
String s = "hello";
change(s);
System.out.println("s = " + s);//s = hello
}
public static void change(String str){
str = str + "atguigu";// str = new String(str +"atguigu");
}
}
变量的分类:
1、成员变量
(1)静态变量
(2)实例变量
2、局部变量
区别:
1、声明位置和方式
(1)静态变量:在类中方法外,并且有static修饰
(2)实例变量:在类中方法外,没有static修饰
(3)局部变量:在方法体{}中或方法的形参列表、代码块中
2、在内存中存储的位置不同
(1)静态变量:方法区
(2)实例变量:堆
(3)局部变量:栈
3、生命周期
(1)静态变量:和类的生命周期一样,因为它的值是该类所有对象共享的,早于对象的创建而存在。
(2)实例变量:和对象的生命周期一样,随着对象的创建而存在,随着对象被GC回收而消亡,
而且每一个对象的实例变量是独立的。
(3)局部变量:和方法调用的生命周期一样,每一次方法被调用而在存在,随着方法执行的结束而消亡,
而且每一次方法调用都是独立。
4、作用域
(1)静态变量和实例变量:不谈作用域
在本类中,唯一的限制,静态方法或静态代码块中不能使用非静态的,其他都可以直接使用。
在其他类中,能不能使用看修饰符(public,protected,private等)
(2)局部变量:有作用域
出了作用域就不能使用
5、修饰符(后面来讲)
(1)静态变量:很多
public,protected,private,final,volatile等,一定有的是static
(2)实例变量
public,protected,private,final,volatile,transient等
(3)局部变量
final
public,protected,private:权限修饰符
final:是否是常量,即值是否可以修改
volatile:和多线程有关
transient:是否序列化,和IO有关
6、默认值
(1)静态变量:有默认值
(2)实例变量:有默认值
(3)局部变量:没有,必须初始化
其中的形参比较特殊,靠实参给它初始化。
参数:形参和实参
三、可变参数:JDK1.5开始
1、什么是可变参数?
它仍然是形参和实参,只不过它是特殊的形参,形如:数据类型… 形参名
2、什么情况下使用形参
当我们在设计一个方法的时候,发现这个方法需要形参,
而且形参的类型可以确定,但是形参的个数不能确定时,就可以使用可变参数。
例如:当我们要设计方法,这个方法可以求任意个整数的和
3、如何使用可变参数?
(1)在设计可变参数的方法中,如何使用可变形参?
把它当做数组使用
(2)在调用时,
①可变形参对应的位置,可以传入0~n个对应类型的实参。
②可变形参对应的位置,可以传入对应类型的数组
4、需要注意的地方
(1)一个方法最多只能有一个可变参数
(2)可变参数必须是最后一个
class VarParam{
public static void main(String[] args){
System.out.println(sum());//传了0个实参
System.out.println(sum(4));//传了1个实参
System.out.println(sum(4,1,2,6,8));//传了5个实参
int[] arr = {1,2,3,4,5};
System.out.println(sum(arr));//传入一个数组
System.out.println("--------------------------");
//System.out.println(max());//错误的
System.out.println(max(4,1,2,6,8));
}
//这个方法可以求任意个整数的和
/*
返回值类型:
需要,结果是和,long
方法名:sum
形参列表:是否需要调用者给我们传递参数,需要,什么类型,int,几个?不知道
*/
static long sum(int... nums){
long he = 0;
for(int i=0; i<nums.length; i++){
he += nums[i];
}
return he;
}
//这个方法可以求1-n个整数的最大值
/*
返回值类型:int
方法名:max
形参列表:至少需要调用者给我传入1个整数
其中int num不是可变参数,
int... args是可变参数
调用时,非可变参数,原来该咋传咋传。
可变参数部分,想咋传咋传,可以传入0~n个对应类型的实参也可以传入对应的数组
*/
static int max(int num, int... args){
int biggest = num;
for(int i=0; i<args.length; i++){
if(biggest < args[i]){
biggest = args[i];
}
}
return biggest;
}
}
形参、实参、可变参数
四、命令行参数:(了解)
1、特殊的形参和实参,它是main方法的形参和实参。
main方法的形参:(String[] args) 或 (String… args)
2、在main中如何使用args,把它当做数组使用
3、如何给main方法传实参
在运行时传入
格式:
java 类名 参数1 参数2 参数3 。。。
class CommandParam{
public static void main(String[] args){
System.out.println("args.length = " + args.length);
for(int i=0; i<args.length; i++){
System.out.println("第" + (i+1) + "个实参是:" + args[i]);
}
}
}
五、方法的重载:Overload
1、定义:
在一个类中,出现了两个或多个的方法,
它们的方法名称相同(因为它们的功能相同),
但是它们的形参列表不同(它们适用于不同的情况),
这样的两个或多个方法就构成了方法的重载。
和返回值类型无关。
class Overload{
public static void main(String[] args){
System.out.println(max(4,6));
System.out.println(max(4.0,6.0));
System.out.println(max(4,5,6));
System.out.println(max(4,6.0));//找兼容的
}
//适用于两个整数求最大值
public static int max(int a ,int b){
System.out.println("两个整数的");
return a > b ? a : b;
}
//适用于两个小数求最大值
public static double max(double a ,double b){
System.out.println("两个小数的");
return a > b ? a : b;
}
public static int max(int a ,int b,int c){
//int max = a > b ? a : b;
//return max > c ? max : c;
System.out.println("三个整数的");
//先用上面的max(a,b)求出a,b的最大值,在用这个最大值和c用上面的max求出最大值
return max(max(a,b),c);
}
}