一、继承

1、什么是继承

继承是一种特性,利用继承可以重用现有类生成新类,也是代码重用的一种体现。

  • 通过关键字extends继承一个已有的类
  • 父类:被继承的类(超类、基类)
  • 子类:新的类(派生类)
  • Java继承的特点:单继承,只有一个直接父类
  • 继承可以持续进行,形成复杂的继承层级结构
  • 如果一个类的声明中没有使用关键字extends,那么这个类被系统默认为是继承了Object父类

2、继承的作用

  • 简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系
  • 提供软件复用功能
  • 通过增强一致性来减少模块间的接口和界面,大大增加程序的易维护性。

3、继承特性

父类中的:

  • public:将被子类继承、直接使用;
  • private:将被隐藏,在子类中无法访问
  • protected:同一包下可以访问,不同包下子类可以访问
  • default:同一包下可以使用,不同包下对子类也隐藏

二、重写

1、什么叫重写

方法重写是指,子类中定义了一个方法,并且这个方法的名字、返回类型、参数类型及参数的个数与父类所继承的方法完全相同。

2、重写的目的及作用

子类可以通过方法重写来隐藏父类的方法,又称为“覆盖”。

  • 通过方法重写,子类可以把父类的状态和行为变成自己的状态和行为
  • 只要父类的方法能够被子类继承,子类就能重写这个方法
  • 一旦子类重写了这个方法,就表示隐藏了所继承的这个方法
  • 如果通过子类对象调用这个方法,那也是调用重写后的方法

3、多态性

调用同一名称的方法,能实现不同需求下的功能

  • 重载——发生在同一类中多态
  • 重写——发生在子类中

三、super关键字

1、应用场景及作用

  • super的使用场合用来访问直接父类隐藏的数据成员,其使用形式如下: super.数据成员
  • 用来调用直接父类中被覆盖的成员方法,其使用形式如下: super.成员方法(参数)
  • 用来调用直接父类的构造方法,其使用形式如下: super(参数) super()

四、向上转型

1、向上转型

向上转型——父类的引用变量可以指向子类的对象 如:


Employee emp = new Salesman(...);


2、特性

引用变量emp由于是按照Employee类型声明的,因此:

  • 只能调用父类的成员方法或公共属性
  • Salesman类型特有的方法和属性则不能使用
  • 子类重写父类方法,调用的是重写后的方法

3、示例


public class Test{
    public static void main(String[] args){
        Employee emp = new SalesMan();
        emp.working();
        emp.salesShow();    //报错,子类特有方法不能调用
        emp.eat();          //eat()没有被重写,输出 emp eating...
    }
}
//输出 salesman working


五、Object类

1、简介

Object类是所有类的超类,也就是说,Java中的每一个类都是由Object类扩展而来的。因而每当你创建一个对象,它都将拥有Object类中的全部方法。

2、常用方法

方法

用途

Object clone()

创建与该对象的类相同的新对象。

boolean equals(Object)

比较两对象是否相等。

void finalize()

当垃圾回收器确定不存在对该对象的引用时,垃圾回收器在对该对象执行垃圾回收前调用该方法。

class getClass()

返回一个对象的运行时类型信息。

int hashCode()

返回该对象的散列码值。

void notify()

激活等待在该对象的监视器上的一个线程。

void notifyAll()

激活等待在该对象的监视器上的全部线程。

String toString()

返回该对象的字符串表示。

void wait()

等待这个对象另一个更改线程的通知。

void wait(long)

等待这个对象另一个更改线程的通知。

void wait(long, int)

等待这个对象另一个更改线程的通知。

3、instanceof说明(了解)

instanceof是一个Java关键字,用于检查一个对象是否是一个类的实例或是其子类的实例。它的语法是 对象 instanceof 类名,返回一个布尔值。

4、final

  • 修饰属性是常量,只能被赋值一次
  • 修饰的方法不能被重写
  • 修饰类不能被继承

六、字符串补充

1、字符串常用比较方法

1.1、常用的字符串比较成员方法有:
  • equals()
  • equalsIgnoreCase()

equalsIgnoreCaseequals方法的功能类似,不同之处是不区分字母的大小写

1.2、equals方法和==的区别


String string1 = "aaa";
String string2 = "aaa";
String string3 = new String("aaa");
String string4 = new String("aaa");
string1 == string2;         //true
string1.equals(string2);    //true
string3 == string4;         //false
string3.equals(string4);    //true


首先,string1 = "aaa";string2 = "aaa";都指向常量池的同一个对象aaa;其调用==和string1.equals(string2)方法其效果是一样的

String string3 = new String("aaa");String string4 = new String("aaa");是在heap堆中创建两个新对象,他们引用的地址是不同的,从而使得==出现不相等的情况。

string3.equals(string4)所引用的对象是同一类对象且属性内容相等(并不一定是相同对象)时返回true, 就出现了上面的结果

String类重写了Object中的equals()方法,源码如下


public boolean equals(Object anObject) {
        if (this == anObject) {     //判断是否指向同一地址
            return true;
        }
        if (anObject instanceof String) {               //判断是否为String类型
            String anotherString = (String)anObject;
            int n = value.length;                   //String底层存的是final char[]
            if (n == anotherString.value.length) {  //遍历数组
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {                  //逐个值比较
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }


1.3、常量池(了解)

Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到常量池中。

Java中基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean。这6种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。 两种浮点数类型的包装类Float,Double并没有实现常量池技术

字符串池是Java为了重用String对象而设置的一个缓存池,字符串池的实现有一个前提条件:String对象是不可变的。因为这样可以保证多个引用可以同时指向字符串池中的同一个对象。如果字符串是可变的,那么一个引用操作改变了对象的值,对其他引用会有影响,这样显然是不合理的

其中需要注意的是:

  • 5大基础类型包装类范围只有[-128,127] Integer i = 127;
• Integer j = 127;
i == j;         //true
Integer x = 128;
Integer y = 128;
x == y;         //false
  • string是不可变的,所以有一个常量缓存池,这也是上面在字符串中==equals有特殊情况的原因

2、StringBuffer类、StringBuilder

由于字符串的底层存储是final char[]型存储,在赋初值以后就是不可变的。如果在项目中需要频繁变动字符串内容,就什么多次开辟新的存储空间,然后重新将变量指向新空间,极度浪费运算资源。

在这种场合下,可以使用StringBuilderStringBuffer来节省资源,且这种类中提供大量便捷操作方法。其底层存储逻辑为char[],并未用final修饰,所以这两个类在变化时就无需频繁执行开空间操作。

二者的区别在于:

  • StringBuilder 并未考虑线程安全问题,虽然速度较快,但不推荐在多线程状况下使用
  • StringBuffer 虽然速度较慢,却是线程安全的
2.1、构造方法

构造方法

说明

StringBuffer()

构造一个没有字符的字符串缓冲区,初始容量为16个字符

StringBuffer(CharSequence seq)

构造一个包含与指定的相同字符的字符串缓冲区 CharSequence

StringBuffer(int capacity)

构造一个没有字符的字符串缓冲区和指定的初始容量。

StringBuffer(String str)

构造一个初始化为指定字符串内容的字符串缓冲区。

2.2、常用方法

方法

说明

append(String str)

将指定的字符串附加到此字符序列。

capacity()

返回当前容量。

deleteCharAt(int index)

删除 char在这个序列中的指定位置。

insert(int offset, char c)

在此序列中插入 char参数的字符串表示形式。

2.3、示例


package com.woniu.Zhang;

public class BuilderApp {
    
    public static void main(String[] args) {
        StringBuilder s1 = new StringBuilder();
        StringBuilder s2 = new StringBuilder(11);
        StringBuilder s3 = new StringBuilder("hello");
        
        System.out.println(s1.length());
        System.out.println(s1.capacity());
        
        System.out.println(s2.length());
        System.out.println(s2.capacity());
        
        System.out.println(s3.length());
        System.out.println(s3.capacity());
        
        System.out.println("--------------------------");
        
        s3.append("world");
        System.out.println(s3.length());
        System.out.println(s3.capacity());
        
        System.out.println("-----------------------------");
        
        s3.append("123456789123");
        System.out.println(s3.length());
        System.out.println(s3.capacity());
    }

}
输出:
0
16      //默认开辟长度为16的空间容量
0
11      //可手动设置长度
5
21      //new时新增的字符串,容量为新字符串长度+16
--------------------------
10
21      //未超出当前空间容量,容量不变
-----------------------------
22
44      //超出现有空间长度,直接开辟空间新长度*2