面向对象的三大特征
继承 extends
继承基类的方法,并做出自己的改变或扩展;子类共性的方法或者属性可以直接使用父类的,而不需要自己再定义,只用扩展自己的个性化操作
- 父类也称作超类、基类、派生类等。
- Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护
- Java中类没有多继承,接口有多继承。
- 子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法)。父类私有的属性和方法不可以直接访问
- 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object
instanceof是二元运算符
左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false
public class Test{
public static void main(String[] args) {
Student s = new Student("张三",172,"Java");
System.out.println(s instanceof Person);
System.out.println(s instanceof Student);
}
}
方法的重写 override
子类通过重写父类的方法,可以**用自身的行为替换父类的行为**。方法的重写是实现多态的必要条件
- 方法名、形参列表相同
- 返回值类型和声明异常类型,子类小于等于父类
- 访问权限,子类大于等于父类
public class TextFour {
public static void main(String[] args) {
horse h = new horse();
h.run();
h.stop();
}
}
class jiaotong{
public void run() {
System.out.println("run");
}
public void stop() {
System.out.println("stop");
}
}
class horse extends jiaotong{
public void run() { //方法名、形参列表相同
System.out.println("跑");
}
}
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来访问父类中被子类覆盖的方法或属性(不能调用父类的私有属性)
构造方法第一句总是:super(…)来调用父类对应的构造方法 继承树追溯流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止。
public class TestSuper02 {
public static void main(String[] args) {
System.out.println("开始创建一个ChildClass对象......");
new ChildClass();
}
}
class FatherClass {
public FatherClass() {
System.out.println("创建FatherClass");
}
}
class ChildClass extends FatherClass {
public ChildClass() {
//super(); 默认调用父类对象
System.out.println("创建ChildClass");
}
}
封装
高内聚,低耦合,提高代码的安全性,复用性
- private 表示私有,只有自己类能访问
- default表示没有修饰符修饰,只有同一个包的类能访问
- protected表示可以被同一个包的类以及其他包中的子类访问
- public表示可以被该项目的所有包中的所有类访问
- 默认Default
封装的意义:
明确标识出外部使用的所有成员和数据项;内部细节对外部透明,外部调用无需关心内部实现
比如:Javabean的调用,Javabean的属性都是私有的,提供get/set方法对外访问
类的属性的处理:
- 一般使用private访问权限。
- 提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操
一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰
//Java bean实例封装
public calss person{
//属性一般用private修饰
private int id;
private string name;
private int age;
public void setName(String name){
this.name = name; //外部类要调用name就要通过这个方法
}
public void getName(String name){
return this.name;
}
public void setAge(int age){
this.age = age;
}
}
多态
多态指的是同一个方法调用,由于对象不同可能会有不同的行为
多态的要点
- 多态是方法的多态,不是属性的多态(多态与属性无关)
- 存在要有3个必要条件:继承,方法重写,父类引用指向子类对象
- 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了
注:无法调用子类特有的功能方法,只能调用继承父类重写的方法
父类引用指向子类对象,向上转型,属于自动类型转换。
public class TestPolym {
public static void main(String[] args) {
Animal a1 = new Cat(); // 向上可以自动转型
animalCry(a1);
Animal d= new Dog(); //这里把dog方法自动转型为animal方法了
Dog d2= (Dog)d; //要使用子类对象 还要强制向下转型回来
d2.resp();
}
// 有了多态,只需要让增加的这个类继承Animal类就可以了。
static void animalCry(Animal a) {
a.shout();
}
}
class Animal {
public void shout() {
System.out.println("叫了一声!");
}
}
class Dog extends Animal { //继承
public void shout() { //重写
System.out.println("旺旺旺!");
}
public void resp(){
System.out.println("看门");
}
}
class Cat extends Animal {
public void shout() {
System.out.println("喵喵喵喵!");
}
}
final关键字的作用
- 修饰变量: 被它修饰的变量不可以指向新的对象。赋了初值,就不能被重新赋值。
- 修饰方法:该方法不可被子类重写。但是可以被重载
- 修饰类: 修饰的类不能被继承。比如:Math、String等
抽象方法
使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。包含抽象方法的类就是抽象类
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用
- 抽象类只能用来被继承。
- 抽象方法必须被子类实现
注:抽象类设计的目的是为了代码复用,当不同的类具有某些相同的行为,且其中一部分行为的实现方法一直时,可以将这些类派生出一个抽象类
当只关注事物的本质时,用抽象类;当关注一个操作的时候,用接口
定义抽象类的难度较高,因为每个类只能实现继承一个类;在这个类中就要继承或编写出子类的所有共性;接口只是定义一个动作,一种规范,一个类可以同时实现多个接口
接口
对子类行为进行约束。全面地实现了:规范和具体实现的分离。接口不提供任何实现,接口中所有方法都是抽象方法。
//格式
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}
定义接口的详细说明
- 访问修饰符:只能是public或默认
- 接口名:和类名采用相同命名机制。
- extends:接口可以多继承
- 常量:接口中的属性只能是常量,总是:默认public static final 修饰(可以省略某一个修饰符)。常量定义后必须赋值。
- 方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。Java8接口中可以含有static和default方法
要点
- 子类通过implements来实现接口中的规范
- 接口不能创建实例,但是可用于声明引用变量类型
一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的;实现类可以获取接口中的属性。
public class TestInterface {
public static void main(String[] args) {
Volant volant = new Angel(); //把angel定义成了volant对象 只能使用volant类的方法
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("我是鸟人,正在飞!");
}
}
```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() {
}
@Override
public void testb() {
}
@Override
public void testc() {
}
}
<a name="z2Eju"></a>
### 内部类
把一个类放在另一个类的内部定义,称为内部类
<a name="rWj4d"></a>
#### 作用
- 内部类提供了更好的封装。**只能让外部类直接访问**,不允许同一个包中的其他类直接访问。
- **内部类可以直接访问外部类的私有属性**,内部类被当成其外部类的成员。 **但外部类不能访问内部类的内部属性**。
```java
//非静态内部类的使用
public class TextInnerClass {
public static void main(String[] args) {
//创建内部类对象
outer.inner inner = new outer().new inner();
inner.show();
}
}
class outer{
int age =10;
class inner{
private int age = 20;
public void show() {
int age = 30;
System.out.println("外部成员变量"+outer.this.age);
System.out.println("内部成员变量"+this.age);
System.out.println("局部变量"+age);
}
}
}
内部类可以分为四种:局部内部类、成员内部类、匿名内部类、静态内部类
局部内部类
存在方法中的内部类,局部内部类的访问权限仅限于方法或作用域内。它不能访问修饰符以及static修饰符,只能访问final变量和形参
成员内部类
定义在另一个类中的类,内部类可以访问外部类的成员和方法,外部类不能直接访问内部类的属性和方法。成员内部类里面是不含静态属性或方法
静态内部类
成员内部类多了一个static修饰符就变成静态内部类了。它一般不依赖于外部类。静态内部类不能使用外部类的非静态变量与方法
匿名内部类
适合只需要使用一次的类。比如:键盘监听操作等。
它作为该实现类的匿名子类对象
//实现匿名内部类
public class TestAnonymousClass {
//接口的声明引用变量类型(引用接口)
public static void test01(Anonymous b) {
b.aa();
}
public static void main(String[] args) {
TestAnonymousClass.test01(new Anonymous(){ //接口没实现不能用 使用匿名内部类就行了
//仅仅使用一次的匿名内部类
@Override
public void aa() {
System.out.println("实现匿名内部类");
}
});
}
}
interface Anonymous{
void aa();
}
注:匿名内部类引用局部变量时,局部变量必须是 final的,为了保证变量在内部类使用时与外部类的一致性(反编译后从字节码层面可见,内部类引用额外生成的类)