面向对象的三大特征

继承 extends

继承基类的方法,并做出自己的改变或扩展;子类共性的方法或者属性可以直接使用父类的,而不需要自己再定义,只用扩展自己的个性化操作

  • 父类也称作超类、基类、派生类等。
  • Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护
  • Java中类没有多继承,接口有多继承
  • 子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法)。父类私有的属性和方法不可以直接访问
  • 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object

instanceof是二元运算符

左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false

  1. public class Test{
  2. public static void main(String[] args) {
  3. Student s = new Student("张三",172,"Java");
  4. System.out.println(s instanceof Person);
  5. System.out.println(s instanceof Student);
  6. }
  7. }

方法的重写 override

  1. 子类通过重写父类的方法,可以**用自身的行为替换父类的行为**。方法的重写是实现多态的必要条件
  • 方法名、形参列表相同
  • 返回值类型和声明异常类型,子类小于等于父类
  • 访问权限,子类大于等于父类
  1. public class TextFour {
  2. public static void main(String[] args) {
  3. horse h = new horse();
  4. h.run();
  5. h.stop();
  6. }
  7. }
  8. class jiaotong{
  9. public void run() {
  10. System.out.println("run");
  11. }
  12. public void stop() {
  13. System.out.println("stop");
  14. }
  15. }
  16. class horse extends jiaotong{
  17. public void run() { //方法名、形参列表相同
  18. System.out.println("跑");
  19. }
  20. }

Object类

所有Java类的根基类,所有的Java对象都拥有Object类的属性和方法。如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。

==和equals方法

“==”代表比较双方是否相同。如果是基本类型则表示值相等如果是引用类型则表示地址相等即是同一个对象

Object 的 equals 方法默认就是比较两个对象的hashcode,是同一个对象的引用时返回 true 否则返回 false。可以根据自己的要求重写equals方法(String就重写了hashcode方法,因为对于两个new的对象,即使它们的字符串是一样的,它们的地址也不相等)

两个对象有相同的hashcode,它们也不一定相等(如哈希冲突,字符串 “BM” 和 “C.” 哈希码相等)

注:String重写了equals方法,它通过把两个字符串内的每一个字符取出来比较;所以两个字符串只要相等,调用equals方法返回的是true

super

是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性(不能调用父类的私有属性)

  1. 构造方法第一句总是:super(…)来调用父类对应的构造方法 继承树追溯流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
  1. public class TestSuper02 {
  2. public static void main(String[] args) {
  3. System.out.println("开始创建一个ChildClass对象......");
  4. new ChildClass();
  5. }
  6. }
  7. class FatherClass {
  8. public FatherClass() {
  9. System.out.println("创建FatherClass");
  10. }
  11. }
  12. class ChildClass extends FatherClass {
  13. public ChildClass() {
  14. //super(); 默认调用父类对象
  15. System.out.println("创建ChildClass");
  16. }
  17. }

封装

高内聚,低耦合,提高代码的安全性,复用性
image.png

  • private 表示私有,只有自己类能访问
  • default表示没有修饰符修饰,只有同一个包的类能访问
  • protected表示可以被同一个包的类以及其他包中的子类访问
  • public表示可以被该项目的所有包中的所有类访问
  • 默认Default

封装的意义:

明确标识出外部使用的所有成员和数据项;内部细节对外部透明,外部调用无需关心内部实现
比如:Javabean的调用,Javabean的属性都是私有的,提供get/set方法对外访问

类的属性的处理:

  • 一般使用private访问权限。
  • 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操
  • 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰

    1. //Java bean实例封装
    2. public calss person{
    3. //属性一般用private修饰
    4. private int id;
    5. private string name;
    6. private int age;
    7. public void setName(String name){
    8. this.name = name; //外部类要调用name就要通过这个方法
    9. }
    10. public void getName(String name){
    11. return this.name;
    12. }
    13. public void setAge(int age){
    14. this.age = age;
    15. }
    16. }

多态

多态指的是同一个方法调用由于对象不同可能会有不同的行为

多态的要点

  • 多态是方法的多态,不是属性的多态(多态与属性无关)
  • 存在要有3个必要条件:继承,方法重写,父类引用指向子类对象
  • 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了

注:无法调用子类特有的功能方法,只能调用继承父类重写的方法

父类引用指向子类对象,向上转型,属于自动类型转换。

  1. public class TestPolym {
  2. public static void main(String[] args) {
  3. Animal a1 = new Cat(); // 向上可以自动转型
  4. animalCry(a1);
  5. Animal d= new Dog(); //这里把dog方法自动转型为animal方法了
  6. Dog d2= (Dog)d; //要使用子类对象 还要强制向下转型回来
  7. d2.resp();
  8. }
  9. // 有了多态,只需要让增加的这个类继承Animal类就可以了。
  10. static void animalCry(Animal a) {
  11. a.shout();
  12. }
  13. }
  14. class Animal {
  15. public void shout() {
  16. System.out.println("叫了一声!");
  17. }
  18. }
  19. class Dog extends Animal { //继承
  20. public void shout() { //重写
  21. System.out.println("旺旺旺!");
  22. }
  23. public void resp(){
  24. System.out.println("看门");
  25. }
  26. }
  27. class Cat extends Animal {
  28. public void shout() {
  29. System.out.println("喵喵喵喵!");
  30. }
  31. }

final关键字的作用

  • 修饰变量: 被它修饰的变量不可以指向新的对象。赋了初值,就不能被重新赋值。
  • 修饰方法:该方法不可被子类重写。但是可以被重载
  • 修饰类: 修饰的类不能被继承。比如:Math、String等

抽象方法

使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。包含抽象方法的类就是抽象类

  • 有抽象方法的类只能定义成抽象类
  • 抽象类不能实例化,不能用new来实例化抽象类
  • 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用
  • 抽象类只能用来被继承。
  • 抽象方法必须被子类实现

注:抽象类设计的目的是为了代码复用,当不同的类具有某些相同的行为,且其中一部分行为的实现方法一直时,可以将这些类派生出一个抽象类
当只关注事物的本质时,用抽象类;当关注一个操作的时候,用接口
定义抽象类的难度较高,因为每个类只能实现继承一个类;在这个类中就要继承或编写出子类的所有共性;接口只是定义一个动作,一种规范,一个类可以同时实现多个接口

接口

对子类行为进行约束。全面地实现了:规范和具体实现的分离。接口不提供任何实现,接口中所有方法都是抽象方法

  1. //格式
  2. [访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
  3. 常量定义;
  4. 方法定义;
  5. }

定义接口的详细说明

  • 访问修饰符:只能是public或默认
  • 接口名:和类名采用相同命名机制。
  • extends:接口可以多继承
  • 常量:接口中的属性只能是常量,总是:默认public static final 修饰(可以省略某一个修饰符)常量定义后必须赋值
  • 方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。Java8接口中可以含有static和default方法

要点

  • 子类通过implements来实现接口中的规范
  • 接口不能创建实例,但是可用于声明引用变量类型
  • 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的;实现类可以获取接口中的属性。

    1. public class TestInterface {
    2. public static void main(String[] args) {
    3. Volant volant = new Angel(); //把angel定义成了volant对象 只能使用volant类的方法
    4. volant.fly();
    5. System.out.println(Volant.FLY_HIGHT);
    6. Honest honest = new GoodMan();
    7. honest.helpOther();
    8. }
    9. }
    10. /**飞行接口*/
    11. interface Volant {
    12. int FLY_HIGHT = 100; // 总是:public static final类型的;
    13. void fly(); //总是:public abstract void fly();
    14. }
    15. /**善良接口*/
    16. interface Honest {
    17. void helpOther();
    18. }
    19. /**Angle类实现飞行接口和善良接口*/
    20. class Angel implements Volant, Honest{
    21. public void fly() {
    22. System.out.println("我是天使,飞起来啦!");
    23. }
    24. public void helpOther() {
    25. System.out.println("扶老奶奶过马路!");
    26. }
    27. }
    28. class GoodMan implements Honest {
    29. public void helpOther() {
    30. System.out.println("扶老奶奶过马路!");
    31. }
    32. }
    33. class BirdMan implements Volant {
    34. public void fly() {
    35. System.out.println("我是鸟人,正在飞!");
    36. }
    37. }

    ```java //接口的多继承 public class TestInterface2 {

} interface a{ void testa(); } interface b{ void testb(); } //接口可以多继承 接口c继承接口a,b interface c extends a,b{ void testc(); }

class test implements c{ @Override public void testa() {

  1. }
  2. @Override
  3. public void testb() {
  4. }
  5. @Override
  6. public void testc() {
  7. }

}

  1. <a name="z2Eju"></a>
  2. ### 内部类
  3. 把一个类放在另一个类的内部定义,称为内部类
  4. <a name="rWj4d"></a>
  5. #### 作用
  6. - 内部类提供了更好的封装。**只能让外部类直接访问**,不允许同一个包中的其他类直接访问。
  7. - **内部类可以直接访问外部类的私有属性**,内部类被当成其外部类的成员。 **但外部类不能访问内部类的内部属性**。
  8. ```java
  9. //非静态内部类的使用
  10. public class TextInnerClass {
  11. public static void main(String[] args) {
  12. //创建内部类对象
  13. outer.inner inner = new outer().new inner();
  14. inner.show();
  15. }
  16. }
  17. class outer{
  18. int age =10;
  19. class inner{
  20. private int age = 20;
  21. public void show() {
  22. int age = 30;
  23. System.out.println("外部成员变量"+outer.this.age);
  24. System.out.println("内部成员变量"+this.age);
  25. System.out.println("局部变量"+age);
  26. }
  27. }
  28. }


内部类可以分为四种:局部内部类、成员内部类、匿名内部类、静态内部类

局部内部类

存在方法中的内部类局部内部类的访问权限仅限于方法或作用域内。它不能访问修饰符以及static修饰符,只能访问final变量和形参

成员内部类

定义在另一个类中的类,内部类可以访问外部类的成员和方法,外部类不能直接访问内部类的属性和方法。成员内部类里面是不含静态属性或方法


静态内部类

成员内部类多了一个static修饰符就变成静态内部类了。它一般不依赖于外部类静态内部类不能使用外部类的非静态变量与方法

匿名内部类

适合只需要使用一次的类。比如:键盘监听操作等。
它作为该实现类的匿名子类对象

  1. //实现匿名内部类
  2. public class TestAnonymousClass {
  3. //接口的声明引用变量类型(引用接口)
  4. public static void test01(Anonymous b) {
  5. b.aa();
  6. }
  7. public static void main(String[] args) {
  8. TestAnonymousClass.test01(new Anonymous(){ //接口没实现不能用 使用匿名内部类就行了
  9. //仅仅使用一次的匿名内部类
  10. @Override
  11. public void aa() {
  12. System.out.println("实现匿名内部类");
  13. }
  14. });
  15. }
  16. }
  17. interface Anonymous{
  18. void aa();
  19. }

注:匿名内部类引用局部变量时,局部变量必须是 final的,为了保证变量在内部类使用时与外部类的一致性(反编译后从字节码层面可见,内部类引用额外生成的类)