一.方法的定义
1.1什么是方法
在Java中采用万物皆对象的思想,此时,方法就是一种行为,也是一种工具,比如,洗衣机有很多功能,比如加洗衣液,洗衣服,甩干这些功能,那么,这些功能就是方法。
1.2方法的定义
修饰符 返回值类型 方法名称 (参数类型 形参) { 方法体代码; return 返回值 } //例子 public int name(int a , int b){ int c = a + b; return c; }二.方法的组成
上面的一个例子中,我们也看到了方法的重要部分为修饰符,返回值类型和方法名称
2.1修饰符
2.1.1控制权限的修饰符
2.1.1.1 public
- 最大的访问范围,可以在任何包,任何类总被访问
- 类:一个java文件中最多能有一个public类,且类名必须和文件名一致
- 成员变量和方法:可以被同一类,同一包,不同包非子类(不同包子类) 访问
2.1.1.2 private
最严格的访问修饰符
- 成员变量:仅限当前类内访问
- 成员方法:仅限类内部调用
- 内部类:仅限外部类内部使用
使用:修饰类成员变量
public class Student { private String nmae; private int age;}成员变量是数据,一般不希望被访问
2.1.1.3 protect
- 同一类中:可以直接访问protected成员
- 同一包中:无论是不是子类均可以访问
- 不同包子类:如果一个类继承自包含protected成员的类(子类和父类不在一个包中),子类可以访问父类中的protected成员
- 不同包的非子类:无法访问,无论是不是子类
2.1.1.4 default
- 当java中未显式调用任何访问修饰符时,则会自动调用default
- default和protect的区别就是在不同包中,protect可以访问子类,而default不能
- 同时要注意default在不加修饰符时会默认添加,而不可以手动添加
2.1.2 非访问修饰符
2.1.2.1 static关键字
- 静态变量 (类变量)
静态变量属于类,在类创建时就会分配内存,而不是某个对象,无论创建多少个对象,静态变量在内存中都只有一份拷贝
访问方式:可以直接通过类进行调用,也可以通过对象进行调用,不过一般推荐通过类直接进行调用
class Example { public static int count = 0; // 静态变量 public Example() { count++; // 每次创建对象时,count的值加1 } public static void main(String[] args) { Example obj1 = new Example(); Example obj2 = new Example(); System.out.println(Example.count); // 输出2 } }- 静态方法 (类方法)
静态方法同样属于类,而不是类的实例。调用静态方法时,不需要创建类的对象,可以直接通过类名来调用
静态方法只能访问静态成员(静态变量和静态方法),不能直接访问实例成员(实例变量和实例方法),这是因为它们的创建时机不同,静态方法在类创建时就已经分配内存,而实例成员 (实例变量和实例方法) 的创建时机是在对象创建之后,就会导致可能静态方法调用实例成员时实例成员还没有进行创建
class Example { private static int value = 10; // 静态变量 public static int getValue() { // 静态方法 return value; } public static void main(String[] args) { int result = Example.getValue(); // 直接通过类名调用静态方法 System.out.println(result); // 输出10 } }- 静态代码块
静态代码块的作用是在类加载时执行一些初始化操作,并且只会执行一次
执行时机:类加载时自动执行,优先于实例代码块和构造函数
使用场景:用于初始化静态变量
2.1.2.2 final 关键字
- final变量
当final用于修饰变量时,该变量一旦被赋值,就不能再被修改
- final方法
当final修饰一个方法时,这个方法不能被重写,但是可以进行继承和重载
2.2 返回值类型
- 返回值类型要进行严格的匹配:
方法返回值的类型必须和方法声明的返回值类型完全一样,或者是该类型的子类(针对引用类型)
在面对包装类和基本数据类型时,可以进行自动装箱和自动拆箱
public int getPrimitive() { return new Integer(10); // 正确,自动拆箱 } public Integer getWrapper() { return 10; // 正确,自动装箱 }void方法不能有返回值,不过可以使用不带表达式的return语句来提前终止方法
三. 参数传递
3.1. 参数传递机制
Java中的参数传递采用的机制是值传递
3.1.1 内存区域划分
- 堆:
主要用来存储数组以及创建好的实例对象
- 栈:
主要用于存储局部变量、方法调用以及返回值等信息
- 方法区:
用于存储类的结构信息,类变量,类方法(static关键字修饰)
3.1.2 对于基本数据类型和引用数据类型
- 对于基本数据类型:
由于java中采用值传递的机制,而基本数据类型又存储在栈上,为了方便,会直接将基本数据类型的值的副本赋值一份给形参,此时当方法使用结束后,方法会释放内存,此时形参不会传回,实参不会发生改变
- 对于引用数据类型:
Java同一采用值传递,只不过当为引用数据类型时,传递的是一份引用地址的副本,此时只是改变了引用的指向,而对象存储在堆中,此时并没有被做任何修改
- 例子:
下面的例子就可以说明基本数据类型的参数传递和引用数据类型参数传递的区别,首先是值传递,在modifyPrimitive这个方法中,我们将传入的值修改为20,但是返回后num的值仍然是10,而在引用类型的参数传递中,我们将名字Alice传入,此时形参p和实参person都指向了Alice,那么,我们修改p的指向,自然就修改了person的对象,传回时为Bob
class ParameterPassingDemo { public static void main(String[] args) { // 基本数据类型参数传递 int num = 10; System.out.println("基本类型传递前: num = " + num); // 输出10 modifyPrimitive(num); System.out.println("基本类型传递后: num = " + num); // 仍输出10,值未改变 // 引用数据类型参数传递 Person person = new Person("Alice"); System.out.println("引用类型传递前: name = " + person.getName()); // 输出Alice modifyReference(person); System.out.println("引用类型传递后: name = " + person.getName()); // 输出Bob,对象被修改 // 尝试修改引用指向 resetReference(person); System.out.println("尝试重置引用后: name = " + person.getName()); // 仍输出Bob,引用未被重置 } // 修改基本数据类型参数 public static void modifyPrimitive(int value) { value = 20; // 修改的是副本,不影响原始值 } // 修改引用数据类型参数 public static void modifyReference(Person p) { p.setName("Bob"); // 通过引用副本修改对象内容 } // 尝试重置引用数据类型参数 public static void resetReference(Person p) { p = new Person("Charlie"); // 修改的是引用副本的指向,不影响原始引用 } } class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; }|
|
上面三张图片详细的说明了这个过程
四.方法的重载
- 参数列表必须不同
- 参数的数量,类型或者顺序至少由一项不同
class Example { public int add(int a, int b) { return a + b; } // 两个int public int add(int a, int b, int c) { return a + b + c; } // 三个int public double add(double a, double b) { return a + b; } // 两个double public double add(int a, double b) { return a + b; } // int+double public double add(double a, int b) { return a + b; } // double+int(顺序不同) }- 方法名必须相同
- 返回类型和访问修饰符可以不同,但不能作为重载的依据