
今日学习面向对象的继承,Object类,封装还有多态
继承是面向对象的三大特征之一,继承包含类的继承,接口的继承
1.继承的实现继承为了实现类的扩展,实现代码的重用,关键字extends,英文意思为扩展。
`现在让我们来编写一个关于继承的小例子,父类Person,子类Father。子类继承父类的id,name属性,扩展出babyName属性和work()方法。注意,类只能单继承。在主方法里new一个Father对象,似乎完成了这一行代码,但是报错了。
public class fatherDemo {
public static void main(String[] args) {
Father T1=new Father(1001,"Tom","Jack");
}
}
class Person{
int id;
String name;
public void speak(){
System.out.println("啊啊啊!");
}
}
class Father extends Person{
String babyName;
public void work(){
System.out.println("working!");
}
}
报错显示缺少构造方法,那咱们就来了解一下构造方法。
构造方法也叫构造器。创建对象时会被自动调用,为对象初始化,构造器与类的名称一致。构造方法可以被重载,重载是在类名相同的情况下形参的增减。
现在咱们根据报错修改下代码
class Father extends Person{
String babyName;
public void work(){
System.out.println("working!");
}
public Father(int id,String name,String babyName){
this.id=id;//this表示当前对象,避免程序出现二义性
this.name=name;
this.babyName=babyName;
}
}
instanceof运算符
在某些情况下需要判断对象是否是是由类或者子类创建的,可以使用instanceof运算符
public class instanceofDemo {
public static void main(String[] args) {
Father f1=new Father(1001,"张三","小明");
System.out.println(f1 instanceof Father);
System.out.println(f1 instanceof Person);
}
}
方法的重写
重写不同与重载,听起来很像,其实毫无关系。重载是参数的不同,而重写是以自己的方法,覆盖父类的同名方法。
tips:
1.方法名,形参相同
2.返回值类型和声明类型,子类不能大于父类
3.访问权限子类大于等于父类
``
public class overrideDemo {
public static void main(String[] args) {
Animal a1=new Animal();
Animal a2=new monkey();
a1.speak();
a2.speak();
}
}
class Animal{
public void speak(){
System.out.println("嘿嘿!");
}
}
class monkey extends Animal{
public void speak(){//重写父类的方法喽
System.out.println("吱吱!");
}
}
final
修饰变量:变量不可被修改
修饰方法:方法不可被重写
修饰类:类不可被继承
代码复用还可以用组合来实现
原理为将父类的对象作为子类的属性调用
public class Animal {
public static void main(String[] args) {
jinmao j1 = new jinmao();
j1.d1.shut();
}
}
class Dog {
public void shut() {
System.out.println("汪!");
}
}
class jinmao {
Dog d1 = new Dog();
}
组合和继承适用于不同的场景,组合适合has…a,继承适用于is…a的情况
例如:笔记本有芯片,笔记本和芯片可以用组合,泰迪是小狗,泰迪和小狗可以用继承
Object类是所有类的父类,如果类没有继承,默认继承Object类
2.toString方法Object类中已经定义了toString()方法,返回一个地址值,当打印一个对象时,自动调用toString方法,返回地址值
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
我们打印对象不是想得到一个地址值,此时我们需要重写toString()方法。
现在我们回顾一下重写的要点
1.方法名,形参相同
2.返回值类型和声明类型,子类不能大于父类
3.访问权限子类大于等于父类
我们将类名不变,返回值属性变量即可
//一个动物类
public class Animal {
int animalId;
String kind;
@Override
public String toString(){
return "宠物id"+animalId+",种类"+kind;
}
public Animal(int animalId, String kind) {
this.animalId = animalId;
this.kind = kind;
}
}
测试类中new一个对象,传入数据,打印对象,发现此时打印出了输入的1001和泰迪
//测试类
public class Text {
public static void main(String[] args) {
Animal a=new Animal(1001,"泰迪");
System.out.println(a);
}
}
3.equals方法
在java中,需要比较双方是否相等,但不是简单的比值,基本数据类型,如int1=1和int2=1比较是对比数值是否相同,而引用数据类型则是比较地址值。
public class Text {
public static void main(String[] args) {
Animal a=new Animal(1001,"泰迪");
Animal b=new Animal(1001,"泰迪");
System.out.println(a.equals(b));
}
}
此时创建了a,b两个对象,但都是传入了1001和泰迪,这一组数据,为什么比较不相等?
因为此时比较的是两个对象的地址值,对象是上文中的引用类型
当我们需要比较文中数据时,可以重写equals()方法。
此时,重新运行测试类
在IDEA中可以快捷生成toString()和equals()的重写,alt+insert即可
super可以视为对父类对象的引用,如果子类中有父类的方法或属性被重写了,可以直接使用super来调用。
public class Animal {
int animalId;
String kind;
public void shut(){
System.out.println("啊!");
}
}
class Dog extends Animal{
public void shut() {
super.shut();
System.out.println("汪!");
}
}
//测试类
public class Text {
public static void main(String[] args) {
new Dog().shut();
}
}
此时子类中已经覆盖了父类的方法,但可以值接调用父类中的方法
封装是为了封装细节,提高维护性,简化外部调用方便使用。“高聚合,低耦合”
2.控制符
星号表示可以调用的范围
此时代码没有进行封装,年龄我们可以随便设定,没有限制
public class PersonDemo {
public static void main(String[] args) {
Person p=new Person();
p.name="二狗";
p.age=999;
System.out.println(p);
}
}
class Person {
String name;
int age;
@Override
public String toString() {
return "Person [ame=" + name + ", age=" + age + "]";
}
}
当我们引入封装即可解决这个问题
Javabean什么是javabean,简单来说,属性私有化,但你得能让我有方法调用这些属性,即set()和get()。
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
}
现在我们可以试着解决年龄的问题
,在输入年龄的时候加入条件语句,即在javabean中修改setAge()。
public void setAge(int age) {
if (age > 115 || age < 0) {
this.age = 18;
} else {
this.age = age;
}
}
封装完Person类后发现代码报错了
思考一下,是不是因为name和age的被私有化了,不能直接调用?
此时我们可以使用setAge和和setName方法。
public class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
p.setName("二狗");
p.setAge(999);
System.out.println(p);
}
}
此时已经封装完毕了,年龄瞎填的一律18,哈哈哈
多态是一个方法随着对象的不同而有着不同的行为。父类引用指向子类对象时,父类调用子类重写的方法,此时就出现多态了。例如:同样是动物的叫在叫,猫是喵,狗是汪。
tips:
1.多态只是方法哦,属性不要来碰瓷
2.多态需要三个条件:继承,方法重写父类引用指向子类对象
public class Animal {
public void shut(){
System.out.println("啊!");
}
}
class dog extends Animal{
@Override
public void shut() {
System.out.println("汪!");
}
}
class Cat extends Animal{
@Override
public void shut() {
System.out.println("喵!");
}
}
此时new一个dog对象
//测试类
static void animalShut(Animal a){
a.shut();
}
public static void main(String[] args) {
dog d1=new dog();
animalShut(d1);//static所以可以直接调用
animalShut(new Cat());
}
}
此时有朋友可能会不太理解,不是说一个父类的引用指向子类的对象么,咋只是new了个狗呢?
测试代码new一个Dog的对象,调用animalShut方法,传入Animal类型,其实等于做了一个赋值操作Animal a=d;
animalShut(new Cat());则等于Animal a=new Cat();
父类指向子类对象,称为向上转型,是自动类型转换。而向上转型后,只能调用编译类型的方法,不能调用运行时的方法,我们需要强制转换,称为向下转型。
String str = (String) obj;总结
写这玩意儿好难,三小时啊啊啊啊!不想总结了,拜了拜!前三天的有空再补,后面的会持续更新,有问题可以探讨。