有时候,代码写的不少,但有些术语却总是记得不太清楚;有些原理,明明经常用到,但却不太会描述。既然如此,那就记录下来,印象不深的时候再来看看。
1.封装:把对象的属性、操作(或业务)结合为一个整体(class),并尽可能得隐藏内部实现细节,使得对数据的访问只能通过已定义的接口。
public class Person { private String name = "张三"; private int age = 18; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat(){ System.out.println("人要吃东西。"); } }
上述代码中,把姓名、年龄属性和吃饭行为都封装到person类中的做法,叫做是封装。
2.继承:从已有的类中派生出新的类,新的类能吸收已有类中的属性与方法,并能拓展新的能力。被继承的类称之为“父类”或“基类”,派生出的新类称之为该类的子类。
重写:子类对从父类继承而来的方法进行修改,返回值和形参都不能改变(可以用注解@override来校验重写是否成功),子类重写的方法不属于新增的方法,重写又叫做覆盖。特别注意,父类的成员变量和静态变量不会被重写,仅仅会被隐藏,被隐藏的变量无法被访问。
public class Son extends Person { //私有属性无法被继承 private int age = 1; public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重写父类方法 @Override public void eat() { System.out.println(this.getAge() + "岁的儿子" + this.getName() + "说:爸爸,我饿。"); } } public class Test { //测试方法1 @org.junit.Test public void test1() throws Exception { Son son = new Son(); son.eat(); } } 执行结果:1岁的儿子张三说:爸爸,我饿。
上述代码中,父类name属性被子类继承,所以执行结果中,儿子也叫做张三。而eat()方法被重写,子类对象调用的是重写后的eat()方法。
3.重载:在一个类中存在多个方法名称相同,但参数签名不同(参数的个数或者类型不同)。(修饰符、返回值类型可以相同也可以不同)
public class Reload { public static void reload(){ System.out.println("无参重载方法。"); } public void reload(String s){ System.out.println("string参数重载方法。"); } public void reload(String s, int i){ System.out.println("string,int参数重载方法。"); } protected String reload(int i){ System.out.println("int参数重载方法。"); return ""; } } public class Test { @org.junit.Test public void test2() throws Exception { Reload reload = new Reload(); reload.reload(); reload.reload(""); reload.reload("",1); reload.reload(1); } } 执行结果: 无参重载方法。 string参数重载方法。 string,int参数重载方法。 int参数重载方法。
4.多态:允许不同类的对象对同一消息做出响应。即同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。这也意味着一个对象有着多重特征,可以在特定的情况下,表现不同的状态,从而对应着不同的属性和方法。
多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
public class Person { private String name = "张三"; private int age = 18; public Person(){ System.out.println("父类的无参构造器:" + this.getName() + "今年" + this.getAge() +"岁。"); this.eat(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void eat(){ System.out.println("人要吃东西。"); } } public class Son extends Person { //私有属性无法被继承,因为此变量名在父类中存在,故父类中此变量将被隐藏 private int age = 1; public static String addr = "abc"; public Son(){ //在执行子类的构造方法之前,必定先调用父类的构造器,若无显示,则默认调用super() //默认:super(); System.out.println("子类的无参构造器:" + this.getName() + "今年" + this.getAge() +"岁。"); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } //重写父类方法 @Override public void eat() { System.out.println(this.getAge() + "岁的儿子" + this.getName() + "说:爸爸,我饿。"); } } public class Test { @org.junit.Test public void test3() throws Exception { Person person = new Son(); person.eat(); } }
执行结果:
父类的无参构造器:张三今年0岁。
0岁的儿子张三说:爸爸,我饿。
子类的无参构造器:张三今年1岁。
1岁的儿子张三说:爸爸,我饿。
定义父类引用指向子类对象,在创建子类对象时,步骤:
1首先会隐式调用父类无参构造器,于是先打印了“父类的无参构造器:张三今年0岁”。而为何是0岁而不是18岁的原因,是子类中存在age变量与父类同名,故父类的age变量被隐藏。2而在父类构造器中调用了this.eat(),实际调用的还是子类重写后的方法(毕竟调用对象都是子类对象,仅仅引用类型为父类而已),3接着super()构造器执行完成(作用是初始化父类变量和方法等),开始执行子类构造器(先初始化子类变量),4调用子类eat()方法。