面向对象
在面向对象中,class和instance是“模板”和“实例”的关系;
class是一种数据类型,对应的instance就是这中数据类型的实例;
class定义field,在每个instance都会拥有各自的field,且互不干扰;
通过new来创建instance,然后用变量指向它;
访问实例字段的方法,变量名.字段名;
指向instance的变量都是引用变量。
练习:
请定义一个City类,该class具有如下字段:
- name: 名称,String类型
- latitude: 纬度,double类型
- longitude: 经度,double类型
public class Test { public static void main(String[] args){ City bj = new City(); bj.name = "北京"; bj.latitude = 39.903; bj.longitude = 116.401; System.out.printf(bj.name); System.out.printf("location:"+bj.latitude+","+bj.longitude); } } public class City { public String name; public double latitude; //纬度 public double longitude;//经度 }
方法
class里的field定义为private时,外部无法访问class里的field,所以我们需要method来让外部代码可以间接修改field;
定义方法的语法:
修饰符 方法返回类型 方法名(方法参数列表){
若干方法实现语句;
return 方法返回值;
}
如果没有方法返回值,返回类型设置为void,可以省略return
public class Test { public static void main(String[] args){ Person person = new Person(); person.setName("xiaoming"); person.setAge(23); } } public class Person { private String name; private int age; public String getName(){ return this.name; } public void setName(String name){ this.name = name; } public int getAge(){ return this.age; } public void setAge(int age){ if (age < 0 || age > 100){ throw new IllegalArgumentException("invalid age value"); } this.age = age; } }
外部代码不能直接修改private字段,但是可以通过setName()、setAge()来间接修改private字段,外部代码也不能直接读取private字段,但是可以通过getName、getAge间接获取private字段。
调用方法的语法是:实例变量名.方法名(参数);
private方法
私有方法不允许外部调用,只能在类内部被调用。
私有方法要在方法前面加上private;
this变量
this是方法里的一个隐含变量,this始终指向当前实例;
如果命名没有冲突时,可以省略this,但是如果局部变量和字段重名,局部变量的优先级要高,就必须加上this;
方法参数
方法可以包含0或者任意个参数;调用方法时,必须按照参数的定义--传递;
可变参数
可变参数用 类型... 定义,可变参数相当于数组类型; eg:String...
class Group { private String[] names; public void setNames(String... names) { this.names = names; } }
但是在上述的代码中,调用方需要自己先构造String[];
eg:Group g = new Group();
g.setNames(new String[]){"xiaoming","tom"}
另一个问题:传入方可以传入一个null:
Group g = new Group(); g.setNames(null);
可变参数可以保证不能传null,因为传入0个参数时,接收到的实际值是一个空数组而不是null
。
参数绑定
基本类型的参数绑定
public class Main { public static void main(String[] args) { Person p = new Person(); int n = 15; // n的值为15 p.setAge(n); // 传入n的值 System.out.println(p.getAge()); // 15 n = 20; // n的值改为20 System.out.println(p.getAge()); // 15 } } class Person { private int age; public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
修改局部外部变量n之后,不影响实例p的age字段,原因是setAge()方法获得的参数,复制了n的值,因此p.age和局部变量n互不影响。
基本类型参数的传递,是调用方的复制。双方各自修改后,互不影响。
引用类型参数绑定
public class Main { public static void main(String[] args) { Person p = new Person(); String[] fullname = new String[] { "Homer", "Simpson" }; p.setName(fullname); // 传入fullname数组 System.out.println(p.getName()); // "Homer Simpson" fullname[0] = "Bart"; // fullname数组的第一个元素修改为"Bart" System.out.println(p.getName()); // "Homer Simpson"还是"Bart Simpson"? } } class Person { private String[] name; public String getName() { return this.name[0] + " " + this.name[1]; } public void setName(String[] name) { this.name = name; } }
引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方。
构造方法
创建对象实例时,就把内部字段全部初始化为合适的值;
构造方法的名称就是类名,在方法内部,可以编写任意语句。但是和普通方法相比,构造方法没有返回值,也没有void,调用构造方法,必须用new操作符。
public static void main(String[] args){ Person person = new Person("Tom",11); System.out.println(person.getName()); System.out.println(person.getAge()); } } public class Person { private String name; private int age; public Person(String name, int age){ this.name = name; this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } }
默认构造方法
所有的class都有构造方法,如果一个类没有定义构造方法,编译器会自动生成一个默认构造方法,它没有参数,也没有执行语句;如果我们自定义了一个构造方法,编译器不再自动创建默认构造方法。
如果想两个构造方法都使用,那么就把两个构造方法都定义出来。
构造方法中没有初始化字段时,引用类型的默认值是null,数值类型的字段用默认值, int类型的默认值是0,布尔类型的默认值是false。
既对字段初始化,又在构造方法里对字段初始化,字段的初始值由构造方法的代码决定。
java中的执行顺序:先初始化字段,然后执行构造方法。
多构造方法
一个构造方法可以调用其他构造方法,这样的目的是便于代码复用。调用语法是this(...)
练习:请给Person类增加(Sting,int)的构造方法:
public class Test { public static void main(String[] args){ Person ming = new Person("Tim",12); System.out.println(ming.getName()); System.out.println(ming.getAge()); } } public class Person { private String name; private int age; public Person(String name, int age){ this.name = name; this.age = age; } public String getName(){ return name; } public int getAge(){ return age; } }