适用于有其他编程语言基础的Java小白零基础教程(二)

QcrTiMo 发布于 9 天前 14 次阅读


方法

包括:创建实例、定义方法、方法参数、参数绑定、构造方法、方法重载

输出结果都写在了注释中

创建实例

public class demo11{
    // 创建实例(instance)
    public static void main(String[] args){
        // 定义了class,只是定义了对象模版,而要根据对象模版创建出真正的对象实例,必须用new操作符
        // Person ming是定义Person类型的变量ming,而new Person()是创建Person实例
        Person ming = new Person();
        ming.name = "Xiao ming";
        ming.age = 18;
    }
}
class Person {
    // class表示一个类
    // 一个class可以包含多个字段(field),字段用来描述一个类的特征
    // public是用来修饰字段的,它表示这个字段可以被外部访问
    public String name;
    public int age;
}

定义方法(get,set)

public class demo12 {
    // 方法
    public static void main(String[] args){
        Person ming = new Person();
        ming.setName("Xiao ming");
        ming.setAge(18);
        System.out.println(ming.getName() + "," + ming.getAge());
        // Xiao ming,18
    }
}
class Person{
    // 外部代码不能直接读取private字段
    // 但可以通过getName()和getAge()间接获取private字段的值
    // 并且内部方法是可以调用private方法的
    public String name;
    public int age;
    public String getName() {
        return name;    // 相当于this.name
    }
    public void setName(String name) {
        if(name == null||name.isBlank()){
            throw new IllegalArgumentException("invalid name");
        }
        // 在方法内部,可以使用隐含的变量this,它始终指向当前实例
        // 通过this.{field}可以访问当前实例的字段
        // 如果没有命名冲突,可以省略this
        // 如果有局部变量和字段重名,那么局部变量优先级更高,就必须加上this
        this.name = name.strip();   // .strip()去掉收尾空格
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        if(age < 0||age > 100){
            throw new IllegalArgumentException("invalid age value");
        }
        this.age = age;   
    }
}

方法参数

public class demo13 {
    public static void main(String[] args){
        Person ming = new Person();
        // 调用setNameAndAge()方法时,必须有两个参数,且第一个参数必须为String,第二个参数必须为int
        ming.setNameAndAge("Xiao mung", 18);
        Group g = new Group();
        g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 传入3个String
        g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String
        g.setNames("Xiao Ming"); // 传入1个String
        g.setNames(); // 传入0个String
    }
}
class Person{
    private String name;
    private int age;
    //传入两个参数
    public void setNameAndAge(String name,int age){
        this.name = name;
        this.age = age;
    }
}
class Group {
    private String[] names;
    //可变参数
    public void setNames(String... names) {
        this.names = names;
    }
}

参数绑定

public class demo14 {
    // 参数绑定
    public static void main(String[] args){
        Person p  = new Person();
        //基本类型参数传递
        int n = 18;
        p.setAge(n);
        System.out.println(p.getAge());
        // 18
        n = 20;
        System.out.println(p.getAge());
        // 18
        // 从结果可知,修改外部的局部变量n,不影响实例p的age字段
        // 原因是setAge()方法获得的参数,复制了n的值,因此,p.age和局部变量n互不影响
        Person p1 = new Person();
        // 引用参数传递
        String[] fullname = new String[]{"Allen","Smith"};
        p1.setName(fullname);
        System.out.println(p1.getName());
        // Allen Smith
        fullname[0] = "Jhon";
        System.out.println(p1.getName());
        // Jhon Smith
        // 调用方的变量,和接收方的参数变量,指向的是同一个对象
        // 双方任意一方对这个对象的修改,都会影响对方
    }
}
class Person{
    private int age;
    private String[] name;
    public String getName() {
        return this.name[0] + " " + this.name[1];
    }
    public void setName(String[] name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
public class demo15 {
    // String类型参数绑定
    public static void main(String[] args) {
        Person p = new Person();
        String bob = "Bob";
        p.setName(bob);
        System.out.println(p.getName());
        // Bob
        bob = "Alice";
        System.out.println(p.getName());
        // Bob
    }
}
class Person {
    private String name;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

关于引用类型参数传递的详细解释

首先,在Java中,所有参数传递都是

值传递(pass by value)

基本数据类型int​, double​, boolean​ 等):传递的是 数值的副本

引用数据类型(数组、对象等):传递的是 引用的副本(即对象地址的拷贝,不是对象本身)。

String[] fullname = new String[]{"Allen", "Smith"};
p1.setName(fullname);

这里传的是一个数组引用的副本

p1.name​ 和 fullname​ 都指向了 同一个数组对象。

[fullname]  ---->  ["Allen", "Smith"]
                       ↑
[p1.name]  ------------┘
fullname[0] = "Jhon";

这里修改的是数组内部的内容,因此 p1.getName()​ 的输出也变化了,变成了 "Jhon Smith"​。

[fullname]  ---->  ["Jhon", "Smith"]
                      ↑
[p1.name]  -----------┘

总结: 修改数组的元素,相当于修改了同一个内存里的对象。引用本身是复制的,但引用指向的对象是同一个。

String bob = "Bob";
p.setName(bob);

这里bob​是一个String​对象。

p.setName(bob)​,把bob这个引用的副本传入了setName​方法,然后把它赋值给了this.name​。

[bob]    ---->   "Bob"
                   ↑
[p.name]  ---------┘
bob = "Alice";

这里不是修改原来的"Bob"对象。

Java中的String是不可变对象(immutable) ,一旦创建,就不能修改。

bob = "Alice";​这行代码实际上是让bob​这个变量指向了一个新的"Alice"​字符串对象,而不是改变原来的"Bob"对象

[bob]    ---->   "Alice"
[p.name] ---->   "Bob"

总结:String​是不可变对象,bob = "Alice"​是新建对象,跟之前传入p.setName(bob)​没有任何联系。指针断了,所以p.getName()​还是输出"Bob"​。

传递内容结果
基本类型复制值,互不影响
引用类型(数组、对象等)复制引用,指向同一对象,修改对象内容会相互影响
特殊的 String虽然是引用,但不可变,改变变量实际上是指向新的对象,互不影响

构造方法

默认构造方法(无参构造方法)

如果你不写任何构造方法,Java 会给你一个隐式的无参构造器:

public class Animal {
    // Java会自动添加一个public Animal() {}
}
Animal a = new Animal(); // 调用默认构造器

有参构造方法

public class demo16 {
    // 构造方法
    // 是 Java 类中的一种特殊方法,用来创建对象并进行初始化
    public static void main(String[] args) {
        Person p = new Person("Xiao Ming", 15);
        // 如果我们自定义了一个构造方法,那么,编译器就不再自动创建默认构造方法
        // Person p = new Person(); 编译错误:找不到这个构造方法
        System.out.println(p.getName());
        System.out.println(p.getAge());
    }
}
class Person {
    private String name;    // 默认初始化为null
    private int age;    // 默认初始化为0
    // 构造方法的名字必须和类名相同,且没有返回类型(连void也没有)
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return this.name;
    }
    public int getAge() {
        return this.age;
    }
}

方法重载

public class demo17 {
    //构造方法的重载
    public static void main(String[] args) {
        Person p1 = new Person(); 
        Person p2 = new Person("Xiaoming",12);
        Person p3 = new Person("Xiaohong"); 
        System.out.println(p1.getAge() +" " + p1.getName());
        System.out.println(p2.getAge() +" " + p2.getName());
        System.out.println(p3.getAge() +" " + p3.getName());
        // 0 Unamed
        // 15 Xiaoming
        // 12 Xiaohong
    }
}
// 构造方法可以重载,同一个类里可以写多个构造方法,只要参数不同
class Person {
    // 可以对字段直接进行初始化
    private String name = "Unamed";
    private int age = 0;
    // 无参构造法
    public Person() {
    }
    // 有参构造法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 不同参数的有参构造法
    public Person(String name) {
        this.name = name;
        this.age = 12;
    }
    public String getName() {
        return this.name;
    }
    public int getAge() {
        return this.age;
    }
}

此外,String​类提供了多个重载方法indexOf()​,可以查找子串的索引:

int indexOf(int ch)​:根据字符的Unicode码查找;

int indexOf(String str)​:根据字符串查找;

int indexOf(int ch, int fromIndex)​:根据字符查找,但指定起始位置;

int indexOf(String str, int fromIndex)​根据字符串查找,但指定起始位置。

public class demo18 {
    public static void main(String[] args){
        String s = "Hello JavaWorld!";
        int n1 = s.indexOf('a');
        int n2 = s.indexOf("llo");
        int n3 = s.indexOf('o',5);
        System.out.println(n1 + "n" + n2 + "n" + n3);
        // 7
        // 2
        // 11
    }
}

斯哈斯哈斯哈,佳代子啊啊啊啊啊啊ᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗᕕ(◠ڼ◠)ᕗ
最后更新于 2025-05-19