一,继承
1,向上转型
子类对象可以当做父类对象使用,因为父类有的功能子类都有;
父类对象不能当子类使用,因为子类有的功能父类不一定有;
父类变量引用子类对象时,不能调用子类特有方法,因为编译时会报错;
2,强制类型转换
子类当父类来使用时,如果想调用子类特有方法,需要强制类型转换为子类,才能 调用;
如果父类变量记住的是父类对象,这时不能强转;
强转的代码在编译时不会报错,通常会用instanceof判断之后再进行强转;
例如: class Person {} 定义一个人类
class Student extends Person {} 定义一个学生类继承人类
class Demo {
Person p = new Student(); 是向上转型,子类当父类使用
If(p instanceof Student ) 使用instanceof判断p是否属于学生类
return Student s = (Student ) p; 如果是,则强转
}
3,重写方法
子类可以重写父类方法,一旦重写,调用时就会找子类重写后的方法;
如果需要调用父类被覆盖的方法,可以使用super关键字;
重写方法时,返回值类型和参数列表必须全部相同,访问权限不能更低;
访问权限排列:
public > protected > default > private
4,@Override
注解,加载方法前,用来检查当前方法是否覆盖父类的一个方法
如果成功覆盖,编译会通过;如果没有覆盖,编译会报错;
class Demo {
public static voidmain(String[] args) {
//子类对象当父类对象使用
Person p = new Student();
//父类变量使用子类特有方法,会报错
//p.study();
//使用instanceof判读变量类型,如果是,父类变量强制转换成子类变量;
if( p instanceof Person) {
Student s =(Student)p;
s.study();
}
else
System.out.println("不是Person类型,不能转换");
}
}
class Person {
String name;
int age;
public void eat() {
System.out.println("吃饭");
}
}
class Student extends Person {
//检测子类的eat方法是否覆盖了父类的eat方法
@Override
//父类中的eat方法重写
public void eat() {
System.out.println("Student吃饭");
}
public void study() {
System.out.println("学习");
}
}
二,组合设计模式
1,什么是组合设计模式
当定义一个类需要使用另一个类的方法时,就可以使用组合设计模式;
2,组合设计模式的写法
定义成员变量,用来引用被组合的对象;
构造函数接收一个被组合的对象,用成员变量引用;
在需要使用被组合类的方法时,通过成员变量调用被组合对象的方法;
3,组合和继承的区别:
在两个类没有逻辑上的父子关系,不适合使用继承,就使用组合设计模式;
Java只支持单继承,组合不占用继承的位子;
如果使用继承,子类可以当做父类使用,支持了多态;
4,组合,继承分别在什么情况下使用
在定义类需要使用另一个类的方法时,这两种方式都可以实现;
如果定义的一个类要当做另一个类使用,就必须使用继承;
如果不需要使用父类,建议使用组合;
class CompositeDemo {
public static voidmain(String[] args) {
Card c = new Card();
c.save(6000);
Person p = new Person(c);
p.shopping();
p.eat();
System.out.println("卡里还剩: " + c.getBalance());
}
}
class Person {
private Card card; // 1.定义成员变量,用来引用被组合的对象
public Person(Card card){ // 2.构造函数接收一个被组合的对象,用成员变量引用
this.card = card;
}
public void shopping() {
card.spend(5000); // 3.通过成员变量调用被组合对象的方法
System.out.println("买了一台iPhone5");
}
public void eat() {
card.spend(500);
System.out.println("吃了一顿全聚德");
}
}
class Card {
private int balance; //卡的余额
public void spend(intamount) { //刷卡消费, amount为金额
System.out.println("刷卡消费,花了" +amount + "元");
balance -= amount;
}
public void save(intamount) {
balance += amount;
}
public int getBalance(){
return balance;
}
}
三,垃圾回收
1,对象的销毁
对象的生命周期从new建立对象开始,在没有任何数据指向的时候生命周期结束;
当一个对象生命周期结束的时候,它就成为了一个垃圾对象,垃圾对象并不是立即就回收;
Java程序中的垃圾对象是在占用空间过大的时候,才会由垃圾回收器回收;
2,finalize
finalize是Object的一个类,所有的类都会继承到这个方法;
在对象销毁之前就会执行它;
3,手动清理垃圾
System.gc()可以通过垃圾回收器回收程序中的垃圾对象;
class GcDemo {
public static voidmain(String[] args) throws Exception {
//循环,建立1000个无指向的newPerson对象
for(int x=0; x<1000; x++)
new Person();
//通知垃圾回收器清理垃圾,异步方法,销毁需要一段时间
System.gc();
//当前程序休眠1000毫秒;
Thread.sleep(1000);
System.out.println(Person.x);
}
}
class Person {
//用来统计person类中对象的数量;
public static int x;
public Person() {
//每创建对象时自增;
x++;
}
@Override
//重写object类的对象,对象被销毁之前执行;
public void finalize() {
//每销毁对象时自减;
x--;
}
}
四,对象转字符串
1,Object类的toString()
Object类的toString()会被所有的类继承,这个方法可以将对象转为字符串
默认返回“类名@地址”;
2,自定义toString()
如果我们定义一个类,希望别人使用的时候不返回地址,可以重写toString()方法,在toString()中返回希望我们返回的值,例如返回对象的属性值
3,System.out.println()
这个方法打印一个对象的时候,默认会调用对象的toString(),打印其返回值;
class ToStringDemo {
public static voidmain(String[] args) {
Person p = new Person();
p.name ="传智";
p.age =12;
System.out.println(p);
}
}
class Person {
String name ;
int age;
//检测子类方法是否覆盖了当前父类的方法
@Override
//重写object类中的toString()方法,
public String toString(){
return name +" , "+age;
}
}
五,对象的比较
1,使用==进行比较对象
在java中使用==比较2个对象时是比较2个对象的地址是否相同,也就是判断2个对象是否是同一个类;
通常我们希望比较2个对象的内容(成员变量)是否完全相同,就无法使用==进行比较了
2,equals比较
Object类中提供了equals方法用来比较对象,但其默认的实现是比较地址,如果我们不想比较地址,可以在类中重写该方法;
在equals中比较2个类的属性是否完全相同;
class Equals {
public static voidmain(String[] args) {
Person p1 = new Person("李斯",21);
Person p2 = new Person("李斯",21);
//比较地址值是否相同;
System.out.println(p1 == p2);
//使用自定义的equals比较属性是否完全相同
System.out.println(p1.equals(p2));
}
}
class Person {
//成员变量通常都私有化
private String name;
private int age;
//创建person有参构造函数
public Person(Stringname, int age) {
this.name = name;
this.age = age;
}
//检测当前类是否重写当前父类的方法;
@Override
//核心代码,增加判断条件,提高代码的健壮性;
public booleanequals(Object obj) {
//地址相同,代表传入的是同一个对象,不用比较,直接返回true
if(this == obj)
return true;
//如果传入的对象为null,不用比较,直接返回false
if(obj == null)
return false;
//如果obj不是person类型,不用比较,直接返回false
if(!(obj instanceof Person))
return false;
//为了访问name和age,将object类的实参强转回person类型
Person other = (Person)obj;
//如果名字一个为null,另一个不为null,返回false
//如果2个那么都为null,返回true;
if(this.name == null) {
if(other.name !=null)
return false;
}
//如果name不同,返回false,
//这里的equals调用的是object类中string的equals;因为name的类型是String
if(!this.name.equals(other.name))
return false;
/*name不同,返回false
if(this.name != other.name)
return false;*/
//age不同,返回false
if(this.age != other.age)
return false;
//上面没有返回,就代表成员变量相同,返回true;
return true;
}
}