一、继承
1、private 小坑过
父类私有的方法,子类无法继承。但是父类私有的成员属性,子类是继承了的,通过公开的方法区访问。
public class ExtendsTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.run();
}
}
------------------------------------------------
public class Animal{
void run() {
// private void run() {
//报错:The method run() from the type Animal is never used locally
System.out.println("running");
}
}
class Dog extends Animal{
}
2、super是什么东西?
super()的用法:
1、在构造方法中只能出现一次,且是第一条语句
2、super()只能用在构造方法中,其他地方不行。
super:
1、可以在成员方法中使用,可以通过super直接访问子类继承的父类的方法。静态的方法也是可以使用super访问的,但super不代表类名。
2、super是可以省略的,但是在一种情况下,不能省略:
当父类和子类中拥有同样的方法时,要区分子类和父类中的方法,如果是子类的,this.方法(),这个this是可以省略的。如果是父类的方法,super.方法(),super不能省略。
3、对于静态方法来讲,它是类级别的,与this、super无关。不能用this去掉静态的方法,因为静态方法中没有this这个参数。super是可以调用静态方法的,但是它只是代表了父类的名字。
public class ExtendsTest {
public static void main(String[] args) {
Dog dog = new Dog(18,"小牛");
dog.run();
}
}
----------------------------------
/*我是父类的无参构造
父类得work
sleep!!!
eat
我是子类的有参构造
running
*/
----------------------------------
public class Animal{
private int age;
private String name;
public Animal() {
System.out.println("我是父类的无参构造");
}
public Animal (int age,String name) {
this.age = age;
this.name = name;
System.out.println("父类有参构造");
}
void run() {
System.out.println("running");
}
public void work() {
System.out.println("父类得work");
sleep();
eat();
}
public static void eat() {
System.out.println("eat");
}
private void sleep() {
System.out.println("sleep!!!");
}
}
class Dog extends Animal{
public Dog() {
System.out.println("我是子类的无参构造");
}
public Dog(int age, String name) {
//work(); 子类的work方法,this.方法(),这个this是可以省略的
super.work(); // super.方法()不能省略。
System.out.println("我是子类的有参构造");
}
}
3、this( )
this()
它代表的是当前的构造方法,只能在构造方法中用。它的作用是一个构造方法调用另一个构造的时候使用。
无参构造里的this.name = "小黑" 没有赋值
public class User
{
private int id;
private String name;
public User() {
super();
// this(0, "用户"); 这样调用会很常见,尤其是在源码中。
this.name = "小黑";
}
public User(int id, String name) {
// this(); 这样调用意义不大
this.id = id;
this.name = name;
}
public static void main(String[] args)
{
User user = new User(1,"小牛");
System.out.println(user);
}
public String toString() {
return "id= " + id + ", " + "name= " + name;
}
}
id= 1, name= 小牛
二、Object类
object类是所有类的基类,java中只支持单继承,所以说Object类是最高层的父类。
省略了继承Object类的语法是extends Object。
public class Test {
private String name;
public Test() {
}
public Test(String name) {
this.name = name;
}
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.toString());
}
}
Test@372f7a8d
Test直接调用了toString()方法,一定是从 Object父类中来的。
Object.java源码中的toString()方法:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
三、多态
1、方法的重写
方法的重写发生的条件:
1、方法名、参数列表、参数位置、返回值类型一定要相同(有继承关系的引用进行自动类型转换不会报错)
2、方法的权限,重写只能更高,不能更低,也就是说public修饰的方法,重写的时候不能低于public权限,否则报错。
3、private修饰的方法不能被重写
4、重写后的方法抛出的异常不能更多,只能更少
5、一定要有继承关系,才有重写的概念。
2、多态的好处
OCP: open close principle
23种设计模式中的七大原则中著名的开闭原则
开:对扩展开放
闭:对修改关闭
意思就是:在扩展功能的,增加这功能的时候,支持程序扩展新的功能,但是不要去更改程序中原有的代码
因为:原有的代码已经能够正常的运转,如果你增加功能的时候,修改了原有的代码逻辑,在原有的代码基础上增加了很多代码,就有可能造成更多的bug。这样的话破坏了软件的稳定性。扩展功能,最好的方式是,要求不更改原有的代码,但又能够扩展功能。这是开闭原则。也就是说把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
只修改方法的实现,不必修改方法的声明
3、认识多态
继承是多态产生的前提条件!!!
多态中成员访问特点:
-
成员变量:编译看左边,执行看左边
-
成员方法:编译看左边,执行看右边
-
成员方法有重写,但是成员变量中没有
编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给变量的对象决定。
如果编译时类型和运行时类型不同,就出现多态。
分类:
编译时多态:方法重载
运行时多态:方法覆写
父类型引用指向子类型对象
Animal a = new Dog();这也叫做自动类型转换。
//Dog dog = new Animal; // X,子类型的引用指向父类型的对象
package Hello;
public class hello {
public static void main(String[] args) {
System.out.println("hello!");
Zoo p = new Zoo();//管理员p
Animal a = new Animal();
p.feed(a);
/* 管理员正在给 Hello.Animal@3941a79c 喂食
我是动物,我在吃东西!*/
Animal d = new Dog();
p.feed(d);
/*管理员正在给 Hello.Dog@4fca772d 喂食
小狗正在吃骨头*/
Animal c = new Cat();
p.feed(c);
/*管理员正在给 Hello.Cat@3d494fbf 喂食
猫想要吃鱼*/
Object obj = new Cat();
// obj.eat(); 不可以,因为父类中没有eat方法,子类eat()方法重写变得更加强大
}
}
class Animal{
// private String name;
// private String type;
public Animal(){}
// public Animal(String name, String type) {
// this.name = name;
// this.type = type;
// }
public void eat() {
System.out.println("我是动物,我在吃东西!");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("小狗正在吃骨头");
}
public void gateGard() {
System.out.println("小狗看门");
}
}
class Cat extends Animal {
public void eat() {
System.out.println("猫想要吃鱼");
}
}
class Zoo {
/*
public void feed(Dog dog) {
System.out.println("管理员正在给 " + dog + " 喂食");
dog.eat();
}
public void feed(Cat cat) {
System.out.println("管理员正在给 " + cat + " 喂食");
cat.eat();
}
*/
public void feed(Animal animal) {
System.out.println("管理员正在给 " + animal + " 喂食");
animal.eat();
}
}
类型转换异常:ClassCastException
//报错:Exception in thread "main" java.lang.ClassCastException:
Dog xn = (Dog) a; //强制类型转换
xn.gateGard();
Exception in thread "main" java.lang.ClassCastException:
class Zoo {
public void feed(Animal animal) {
System.out.println("管理员正在给 " + animal + " 喂食");
Dog dog = (Dog) animal;
// 编译时是通过的,运行时抛出异常ClassCastException
dog.eat();
}
}
避免类型转换异常:instanceof
语法:
(引用 instanceof 类型) 结果为boolean
为什么要强制类型转换,我们已经说过了,就是要用多态机制,同时子类对象又要访问自己特有的属性和方法的时候,就要使用强制类型转换。
强制类型转换的前提是,要有继承关系。
class Zoo {
public void feed(Animal animal) {
System.out.println("管理员正在给 " + animal + " 喂食");
// 解决ClassCastException的办法
if(animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.eat();
dog.gateGard();
}
else if(animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.eat();
cat.catchMouse();
}
else
{
animal.eat();
}
}
}
实现多态的机制:
父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。