Java面向对象编程总结

1、 包

1.1 包 (package) 是组织类的一种方式。
包可以理解为其实就是文件夹(文件目录)。

1.2 包的命名:通常会用公司的域名的颠倒形式。包名要和代码路径相匹配. 例如创建 com.bit.demo1 的包, 那么会存在一个对应的路径 com/bit/demo1 来存储代码

1.3 常见系统包:

  1. java.lang:系统常用基础类(String、Object),此包从JDK1.1后自动导入。
  2. java.lang.reflect:java 反射编程包;
  3. java.net:进行网络编程开发包。
  4. java.sql:进行数据库开发的支持包。
  5. java.util:是java提供的工具程序包。(集合类等) 非常重要
  6. java.io:I/O:编程开发包

1.4 包的访问权限控制:我们已经知道了public和private成员只能被类的内部使用,如果某个成员不包含public、private修饰,那么这个成员可以在这个包内部被其他的类访问,但不能被包外部的类访问,即包访问权限(或默认权限,default)。

2、继承

2.0、 继承为了代码复用
(is - a 的关系)

2.1、 关键字: 子类(派生类) extends 父类
使用 extends 指定父类.

2.2、 子类继承了父类的什么
继承了除构造方法外所有的东西,帮助父类进行构造
子类会继承父类的所有 public 的字段和方法,对于父类的 private 的字段和方法, 子类中是无法访问的,子类的实例中,也包含着父类的实例。可以使用 super 关键字得到父类实例的引用

2.3、 可以使用 super 关键字得到父类实例的引用(必须放在第一行

2.4、 子类构造必须先要构造父类

2.5、 基类 / 父类只能访问自己的成员

2.6、 Java是单继承,只能继承一个类,要实现多继承可以使用接口
Java 中一个子类只能继承一个父类 (而C++/Python等语言支持多继承)

2.7、 继承方式还有多层继承, 即子类还可以进一步的再派生出新的子类,一般我们不希望出现超过三层的继承关系. 如果继承层 次太多, 就需要考虑对代码进行重构了

2.8、 protected:多用在继承
对于类的调用者来说, protected 修饰的字段和方法是不能访问的
对于类的 子类同一个包的其他类 来说, protected 修饰的字段和方法是可以访问的

在这里插入图片描述

小结

Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): default:类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问

继承相关的代码练习:

Animal.java

public class Animal {
    protected String name;
    private int age;
    static {
        System.out.println("Animal::static{}");
    }
    {
        System.out.println("Animal::instance{}");
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Animal(String,int)");
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void eat() {
        System.out.println(this.name+"eat()");
    }

    /*public void sleep() {
        System.out.println("sleep()");
    }*/
}

Cat.java

public class Cat extends Animal{
    private String sex;
    static{
        System.out.println("Cat::static{}");
    }
    {
        System.out.println("Cat::instance{}");
    }

    public Cat(String name, int age, String sex) {
        super(name, age);//必须放在第一行
        this.sex = sex;
        System.out.println("Cat(String,int,String)");
    }
/*    public void func(){
        super.sleep();
        int a = super.a;
    }*/
}

Dog.java

public class Dog extends Animal{
    private String sex;
    static {
        System.out.println("Dog::static{}");
    }
    {
        System.out.println("Dog::instance{}");
    }

    public Dog(String name,int age,String sex) {
        super(name,age);
        this.sex = sex;
        System.out.println("Dog(String,int,String)");
    }
    public void bark(){
        System.out.println(this.name + "wangwang");
    }
}

Test.java

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat("咪咪",2,"man");
        cat.eat();
        System.out.println("=================");
        Cat cat2 = new Cat("咪咪",2,"man");
        /*Dog dog = new Dog("豆豆",3,"man");
        dog.eat();
        dog.bark();*/
    }
}

3、组合

3.0、 final 关键字
曾经我们学习过 final 关键字, 修饰一个变量或者字段的时候, 表示 常量 (不能修改)
被final修饰的类叫做密封类,不能被继承,限制 类被继承

3.1、组合
和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果

public class Student {
 ...
}
public class Teacher {
 ...
}
public class School {
 public Student[] students;
 public Teacher[] teachers;
} 

组合
表示 has - a 语义 在刚才的例子中, 我们可以理解成一个学校中 “包含” 若干学生和教师.
继承
表示 is - a 语义 在上面的 “动物和猫” 的例子中, 我们可以理解成一只猫也 “是” 一种动物.
要注意体会两种语义的区别

3.2、代码块:
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。

4、多态

4.1、向上转型: 父类引用子类对象,即用父类的引用, 指向一个子类的实例。父类只能调用父类自己的方法。

向上转型的三种方式:
直接赋值,方法传参,方法返回

运行时绑定:--------> 多态(运行时多态)(动态绑定
动态绑定: 在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为 动态绑定

发生多态:(运行时多态)
1、继承---->父类需要引用子类对象(向上转型)
2、通过父类的引用,去调用子类和父类同名的覆盖方法

构造方法内,可否发生运行时多态?答案:可以(看下面的例子)

在构造器中调用重写的方法(一个坑)
一段有坑的代码. 我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func

class B {
	public B() {
		// do nothing
		func();
 	}
 	public void func() {
 		System.out.println("B.func()");
 	}
}
class D extends B {
 	private int num = 1;
 	@Override
 	public void func() {
 		System.out.println("D.func() " + num);
	}
}
public class Test {
	public static void main(String[] args) {
 		D d = new D();
  	}
}
// 执行结果
D.func() 0 

构造 D 对象的同时, 会调用 B 的构造方法.
B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func
此时 D 对象自身还没有构造, 此时 num 处在未初始化的状态, 值为 0.
结论: “用尽量简单的方式使对象进入可工作状态”, 尽量不要在构造器中调用方法(如果这个方法被子类重写, 就会触发
动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题

注意
1、重写时,方法不能用private
2、子类的方法权限一定要大于父类的方法权限。
(public > protected > default > private)
3、static修饰的方法不能重写,普通方法可以重写

面试题

重写和重载的区别?

重写:方法名相同,参数列表相同,返回值相同 Override
重载:方法名相同,参数列表不同,返回值不作要求 Overload

this和super的区别 ?

this:当前对象的引用
super:获取到父类实例的引用
在这里插入图片描述
在这里插入图片描述
向下转型:慎用,使用之前必须进行一次向上转型

无论是哪种编程语言, 多态的核心都是让调用者不必关注对象的具体类型. 这是降低用户使用成本的一种重要方式

5、抽象类

包含抽象方法的类
1、抽象类的意义:就是用来继承的
2、抽象类本身不能被实例化
3、抽象方法不能是private(私有)的(抽象类里的抽象方法就是为了被继承来重写的,变成private私有了还怎么继承)
4、抽象类只要被继承,一定要重写里面的抽象方法
但是抽象类A继承了抽象类B,不用在A类里重写B里面的抽象方法,但是后面如果还要再继续继承,还是要重写抽象类里的抽象方法的,该来的还是要来
5、抽象类中可以包含其他的非抽象方法, 也可以包含字段. 这个非抽象方法和普通方法的规则都是一样的, 可以被重写, 也可以被子类直接调用
6、抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法。
7、是使用抽象类相当于多了一重编译器的校验(使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了, 使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题)很多语法存在的意义都是为了 “预防出错”, 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不就 相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们. 充分利用编译器的校验, 在实际开发中是非常有意义的

6、接口

1、接口是抽象类的更进一步
2、接口的关键字:interface
3、接口当中的方法,全部不能有具体的实现,都是抽象方法—默认的public 和 abstract
接口中的方法一定是抽象方法, 因此可以省略 abstract
接口中的方法一定是 public, 因此可以省略 public
4、阿里巴巴:接口中的方法尽量简洁
5、接口当中的成员变量public static final
6、类和接口之间的关系—>实现,只要类实现这个接口,那么接口当中的方法必须重写
7、IShape的接口是不可以被实例化的 new
8、implements A,B,C,D,E…
9、Java 中只支持单继承, 一个类只能 extends 一个父类. 但是可以同时实现多个接口, 也能达到多继承类似的效果
10、类和接口是实现,但是接口和接口不能实现,但是接口可以继承接口,接口和接口之间是继承(接口的继承可以看成一个接口扩展了另一个接口),此时接口B就包含了接口A的功能

面试题
抽象类和接口的区别?

核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中不 能包含普通方法, 子类必须重写所有的抽象方法

11、自定义类型比较,需要实现接口Comparable接口,重写compareTo()方法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章