一、继承
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()
equalsIgnoreCase
与equals
方法的功能类似,不同之处是不区分字母的大小写
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[]
型存储,在赋初值以后就是不可变的。如果在项目中需要频繁变动字符串内容,就什么多次开辟新的存储空间,然后重新将变量指向新空间,极度浪费运算资源。
在这种场合下,可以使用StringBuilder
或StringBuffer
来节省资源,且这种类中提供大量便捷操作方法。其底层存储逻辑为char[]
,并未用final
修饰,所以这两个类在变化时就无需频繁执行开空间操作。
二者的区别在于:
- StringBuilder 并未考虑线程安全问题,虽然速度较快,但不推荐在多线程状况下使用
- StringBuffer 虽然速度较慢,却是线程安全的
2.1、构造方法
构造方法 | 说明 |
| 构造一个没有字符的字符串缓冲区,初始容量为16个字符 |
| 构造一个包含与指定的相同字符的字符串缓冲区 |
| 构造一个没有字符的字符串缓冲区和指定的初始容量。 |
| 构造一个初始化为指定字符串内容的字符串缓冲区。 |
2.2、常用方法
方法 | 说明 |
| 将指定的字符串附加到此字符序列。 |
| 返回当前容量。 |
| 删除 |
| 在此序列中插入 |
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