继承(extends)
- 继承的意思即是对一个内容进行扩展构成一个新的内容。
- 比如:动物可以继承扩展为哺乳动物和爬行动物;他们的底层都是相同的,但是总有一些不一样的地方。
- Object类是所有Java类的根基类,也就是所有的Java对象都拥有Object类的属性和方法。
instanceof
instanceof
是二元运算符,左边是对象,右边是类- 当对象是右边类或子类所创建的对象时,返回true,否则false.
// Student类是Person的一个子类
Student s = new Student("zs",190,"c++");
System.out.println(s instanceof Person);
System.out.println(s instanceof Student);
继承使用应注意的要点
- 父类也成为超类、基类、派生类等。
- Java中只有单继承(但是接口可以多继承)。多继承会引起会乱,是的继承链过于复杂,系统难于维护。
- Java中类没有多继承,接口有多继承。
- 子类继承父类,可以得到父类所有属性和方法(除了父类的构造方法),但不见得可以直接访问(父类的私有属性和方法)。
- 在定义类是没有调用 extends ,则他的父类是: java.lang.Object
方法的重写(override)
- 重写的条件
- 方法名和形参列表必须相同。
- 返回值类型和声明异常类型,子类小于等于父类。
- 访问权限,子类大于等于父类。 ```java public class TestOverride { public static void main(String[] args) { Vehicle v1 = new Vehicle(); Vehicle v2 = new Horse(); Vehicle v3 = new Plane(); v1.run(); v2.run(); v3.run(); v2.stop(); v3.stop(); } } class Vehicle { // 交通工具类 public void run() { System.out.println(“跑….”); } public void stop() { System.out.println(“停止不动”); } } class Horse extends Vehicle { // 马也是交通工具 public void run() { // 重写父类方法 System.out.println(“四蹄翻飞,嘚嘚嘚…”); } }
class Plane extends Vehicle { public void run() { // 重写父类方法 System.out.println(“天上飞!”); } public void stop() { System.out.println(“空中不能停,坠毁了!”); } }
3. 继承的方法在使用的时候,必须new.
3. new的时候可以使用 `Vehicle v3 = new Plane();` ,但是在后边的对象转型的时候,必须注意(不能转错类型,因为一个父类可能存在多个子类)。
<a name="7f4b0424"></a>
### 一些基础方法(toString,==,equals)
<a name="aStCJ"></a>
#### toString
1. Object类中定义了 `public String toString()` 方法,其返回值是String类型的。
1. Object类中的toString方法是输出:类名+@+16进制的hashcode
1. 所以在一般使用中toString 方法一般都会被重写。
<a name="f2b4cba0"></a>
#### == 和 equals
1. `==` 海表比较双方是都夏姑娘同。如果是基本类型则表示值相等,如果是引用类型则表示地址相等则为同一个对象。
1. `equals` 方法默认就是比较两个对象的hashcode,是同一个类型的引用时返回true。一般我们会重写equals方法。
1. JDK提供的很多类中都对equals方法进行类重写(重写之后一般都是比较内容值是否相等)。
<a name="829081b9"></a>
### super关键字和继承树
1. super时直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
1. 使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。
1. super()方法构造函数都会默认调用。
1. 继承方法使用的时候会向上寻找我们的调用(继承树回溯)。
<a name="6912abd3"></a>
### 封装
- 提高代码的安全性
- 提高代码的复用性
- “高内聚”:封装细节,便于修改内部代码,提高可维护性。
- “低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。
<a name="f58e1c18"></a>
#### 访问控制
1. `private` 表示私有,只有自己类能访问
- 只能在自己的类中使用,其他地方都不能使用
- 使用范围:同一个类(一个类就是一个.java中的一个class)
2. `default` 表示没有修饰符修饰,只有同一个包的类能访问
- 在变量或者方法没有被修饰的情况下默认为 default 的,这样就最大就只能在同一个包中使用
- 使用范围:同一个类,同一个包(一个包就是package中)
3. `protected` 表示可以被同一个包的类以及其他包中的子类访问(好像不太经常使用)
- 在被 protected 修饰的情况下,变量或者方法就最多被继承它的子类所使用。
- 使用范围:同一个类,同一个包,它的子类(使用 extends 继承了它的子类,这儿的继承也就只能在同一个)
4. `public` 表示可以被该项目的所有包中的所有类访问
<a name="99962c65"></a>
#### 封装的细节
1. 一般使用 `private` 访问权限
1. 提供相应的 get/set 方法来访问相关属性,这些方法通常是public的。
1. boolean 变量的 get 方法是 is 开头的。
1. 一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。
<a name="fd37f62b"></a>
### 多态(polymorphism)
1. 多态是方法的多态,不是属性的多态
1. 多态的存在有三个必要条件:继承,方法重写,父类引用指向子类对象。
1. 父类引用指向子类对象后,该父类引用调用子类重写的方法,此时多态就出现了。
1. 简单来说,多态就是多个子类继承同一个父类,然后对父类中的某个方法都进行了重写(override)。这样就构成了多态。
```java
// 有了多态,只需要让增加的这个类继承Animal类就可以了。
static void animalCry(Animal a) {
a.shout();
}
- 不管是什么动物叫,我们只要把对象传进去,就能发出准确的叫声。
对象的转型(casting)
- 父类引用指向子类对象,我们成这个过程为向上转型,属于自动类型转换。
- 向上转型后的父类引用变量只能调用他编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要强制转型,称之为向下转型。
- 类型转换时应该注意异常的处理。
final关键字
- final修饰的变量不能被二次赋值。
- final修饰的方法,不能被重写。
- final修饰的类不能被继承。
抽象方法和抽象类(abstract)
抽象方法
- 使用abstract修饰的方法,没有方法体,只有声明。
- 定义的是一种规范,告诉子类必须要给抽象方法提供具体的实现。
抽象类
- 包含抽象方法的类就是抽象类。
- 通过abstract方法定义规范,然后要求子类必须定义具体实现
- 通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
抽象类使用要求
抽象方法的类只能定义成抽象类。
- 抽象类不能实例化,也就是不能用
new
来实例化抽象类。 - 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来
new
实例,只能用来被子类调用。 - 抽象类只能用来被继承。
- 抽象方法必须被子类实现。
接口(interface)
- 普通类:具体实现
- 抽象类:具体实现,规范(抽象方法)。
- 接口:规范
接口的定义
声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] { 常量定义; 方法定义; }
访问修饰符:只能时public或者默认(default)。
- 接口名:和类名采用相同的命名机制;首字母大写和驼峰原则;
- extends:接口可以多继承,但是
继承的都是接口
。 - 常量:接口中的属性只能是常量,总是
public static final
修饰的,不写也是如此。 - 方法:接口中的方法只能是
public abstract
,省略的话也是public abstract
,也就意味着方法是抽象的,只需要规范即可,不需要实现。
接口的使用
- 子类通过
implements
来实现接口中的规范。 - 接口不能创建实例,但是可用于声明引用变量类型。
- 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是
public
的。 在JDK1.8后,接口中包含了静态常量,抽象方法,静态方法。不能有普通属性,构造方法。
public class TestInterface { public static void main(String[] args) { Volant volant = new Angel(); volant.fly(); System.out.println(Volant.FLY_HIGHT); Honest honest = new GoodMan(); honest.helpOther(); } } /**飞行接口*/ interface Volant { int FLY_HIGHT = 100; // 总是:public static final类型的; void fly(); //总是:public abstract void fly(); } /**善良接口*/ interface Honest { void helpOther(); } /**Angle类实现飞行接口和善良接口*/ class Angel implements Volant, Honest{ public void fly() { System.out.println("我是天使,飞起来啦!"); } public void helpOther() { System.out.println("扶老奶奶过马路!"); } } class GoodMan implements Honest { public void helpOther() { System.out.println("扶老奶奶过马路!"); } } class BirdMan implements Volant { public void fly() { System.out.println("我是鸟人,正在飞!"); } }
接口的多继承
interface A {
void testa();
}
interface B {
void testb();
}
/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
void testc();
}
public class Test implements C {
public void testc() {
}
public void testa() {
}
public void testb() {
}
}
内部类
非静态/静态内部类
public class TestInnerClass {
public static void main(String[] args) {
Outer outer = new Outer();
/**
* 上边是创建外部类
* 下边创建内部类
*
* 非静态内部类可以直接访问外部类成员,但是外部类不能访问非静态内部类的成员
* 非静态内部类不能有静态方法、静态属性和静态初始化块。
* 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
*/
// 创建非静态内部类
Outer.Inner inner = new Outer().new Inner();
inner.show();
// 创建静态内部类,静态内部类不依托于外部类
Outer2.Inner2 inner = new Outer.Inner2();
}
}
class Outer {
private int age = 10;
public void testOuter() {
System.out.println("Outer.testOuter");
}
class Inner {
int age = 20;
public void show() {
int age = 30;
System.out.println("外部类的成员变量age:" + Outer.this.age);
System.out.println("内部类的成员变量age:" + this.age);
System.out.println("局部变量age:" + age);
}
}
static class Inner2{
}
}
匿名内部类
- 语法:
new 父类构造器(实参类表)\实现接口 () { 匿名内部类类体 }
匿名内部类只使用一次。
public class TestAnnonymousInnerClass { public static void test01(A a){ System.out.println("ajd"); a.aa(); } public static void main(String[] args) { TestAnnonymousInnerClass.test01(new A() { @Override public void aa() { System.out.println("Test"); } }); } } interface A{ void aa(); }
String 基础
String类是不可变字符串,方法在之前写了。
String常用方法
常量池
全局字符串常量池(String Pool)
存放的内容是类加载完成后存到String Pool中的,每个VM只有一份,存放的是字符串常量的引用值。
class文件常量池(Class Constant Pool)
class常量池是在编译的时候每个class都有的,在编译阶段存放的是常量(文本字符串、final常量等)和符号的引用。
运行时常量池(Runtime Constant Pool)
运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。