Java面向对象高级
继承
语法
extends 父类名称
1.子类直接拥有父类中(public protected)的属性和方法
2.改造父类的内容----方法重写
3.不能仅仅为了代码的重用性而继承,必须满足子类 is a 父类的关系
4.Java中是单继承,不能有多个父类
方法重写
1.必须要有父子类
2.子类方法的参数列表和返回值类型必须与父类相同,只有方法体不一样
3.访问修饰符不能比被重写的父类方法的权限更低
public>protected>private
4.声明为static和private的方法不能被重写,但是可以被再次声明
5.一般都添加检测注解@Override【检测重写是否成功】
方法重载与方法重写的区别
位置 | 参数列表限制 | 返回值类型 | 访问权限 | 异常处理 | |
---|---|---|---|---|---|
overload | 一个类中 | 必须不同 | 无关 | 无关 | 与异常无关 |
override | 父子类中 | 必须相同 | 必须一致 | 子类访问修饰符必须>=父类修饰符 | 异常范围更小,但不能出现新的异常 |
super
- super指代父类对象
- super可以调用父类的构造方法,子类的构造方法中,如果没有通过super来调用父类的构造方法,编译器会默认调用父类无参数的构造方法
- super可以调用父类成员方法
- super可以调用父类的属性
多态
概念:同一个行为具有多个不同表现形式或形态的能力
体现:对象的多种表现形式、行为的多种表现形式
对象的多种表现形式
子类都是父类的一种形态,对象的多态性就从此而来
条件:
- 必须要有父子类
- 重写:子类必须重写了父类的方法
- 向上转型:父类的引用指向子类的对象
向上转型是安全的,向下转型具有一定安全隐患,一般需要使用
instanceof
来判断类型
final
修饰变量
该变量不可更改,变为常量,要求变量名称大写,用表达式赋值而不是用最终结果直接赋值。
赋值相关
修饰成员变量的时候必须赋初值
修饰局部变量,在没有使用的时候可以不赋初值。
修饰成员变量(对象):对象的引用不可以修改
修饰方法
方法不能被重写
修饰类
类不能被继承
抽象类
概念:没有方法体的方法就是抽象方法,含有抽象方法的类就是抽象类
- 有抽象方法的类必须是抽象类,需要用abstract来修饰类
- 抽象类不能被实例化
- 子类必须重写父类中的抽象方法,如不重写,子类也只能是抽象类
- final和abstract不能同时存在
- 抽象类也可以有构造方法
接口
概念
如果一个类中的方法均为抽象方法,属性均为全局变量,那么我们可以将这个类定义成一个接口。
interface 接口名称{
全局变量;
抽象方法;
}
接口可以理解为一种特殊的类,里面全部都是全局常量和抽象方法。接口是为了解决Java无法多继承而出现的,但在实际中更多的作用是制定标准。
我们也可以把接口理解为100%的抽象类,因为接口中的方法必须全部是抽象方法。
面向接口编程思想
定义【规范,约束】与实现的分离
优点:
1.降低程序耦合性
2.易于程序扩展
3.有利于程序维护
接口指明了一个类必须做什么、不能做什么
因为接口本身都是由全局常量和抽象方法组成,
所以接口中的成员定义可以简写:
1、全局常量,可以省略public static final 关键字,例如:
public static final String INFO = "内容" ;
简写后:
String INFO = "内容" ;
2、抽象方法,可以省略 public abstract 关键字, 例如:
public abstract void print() ;
简写后:
void print() ;
接口的实现
class 子类 implements 父接口1,父接口2...{
}
//如果一个类既要实现接口,又要继承抽象类,则按以下格式编写:
class 子类 extends 父类 implements 父接口1,父接口2...{
}
接口的继承
//因为接口都是抽象部分,不存在具体的实现,所以允许多继承
interface C extends A,B{
}
如果一个接口想要使用,必须依靠实现类。
实现类(如果不是抽象类的话)要实现接口中的所有抽象方法。
接口中,
所有方法都是抽象的、public的,
所有属性都是public、static、final的
练习
多态的三种常用表达方式分为:
1、普通父类多态
2、父接口多态
3、抽象父类多态
package com.juanfu.pojo;
public class Duotai {
//多态的三种常用表达方式:普通父类多态、父接口多态、抽象父类多态
/*普通父类多态*/
class Animal {
int num = 0;
}
class Cat extends Duotai.Animal {
int num = 1;
}
Animal cat = new Cat();
/*父接口多态*/
interface USB{
void write();
}
class Mouse implements USB{
@Override
public void write() {
System.out.println("鼠标输入数据------------");
}
}
USB Mouse = new Mouse();
/*抽象父类多态*/
abstract class Person{
abstract void run();
}
class Student extends Person{
@Override
void run() {
System.out.println("瞎跑---------");
}
}
Person Student = new Student();
}
}
Object类
Object类是所有类的父类,如果一个类声明了它的父类,那么object就是它的间接父类,如果一个类没有声明它的父类,那么object就是它的直接父类。
因此,以下两种类的定义最终效果是一样的:
class Person { }
class Person extends Object { }
我们还可以使用object类型接收所有类的对象
API
1.getClass()
返回此对象运行时的类
2.toString()
获取对象信息
3.equals()
比较对象内容是否相等
Java提供了丰富的API供我们使用,具体可以查看jdkAPI帮助文档
内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这就是内部类。
广义上的内部类有以下四种:
1.成员内部类
2.局部内部类
3.匿名内部类
4.静态内部类
成员内部类
最普通的内部类,定义在另一个类内部
class Outer {
private double x = 0;
public Outer(double x) {
this.x = x;
}
class Inner { //内部类
public void say() {
System.out.println("x="+x);
}
}
}
特点:成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
不过要注意的是,当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
外部使用成员内部类
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
静态内部类
和成员内部类相似,唯一的不同就是添加了static修饰符。静态内部类不能直接调用外部类非静态的属性和方法,可以调用静态的属性和方法。
静态内部类可以直接创建对象,而成员内部类创建对象需要依赖外部类。
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
例如:
class Person{
public Person() {
}
}
class Man{
public Man(){
}
public People getPerson(){
class Student extends People{ //局部内部类
int age =0;
}
return new Student();
}
}
注意:局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
匿名内部类
- 类只需创建一个对象的时候,可以使用匿名内部类
- 匿名内部类必须继承一个父类或者实现一个接口,当然也只能继承一个父类或者实现一个接口。
- 匿名内部类中不能定义构造函数
- 匿名内部类中不能存在任何静态成员变量和静态方法【JDK16除外】
- 匿名内部类也是局部内部类,局部内部类的所有限制同样对匿名内部类生效。
- 匿名内部类不能是抽象的,它必须实现继承的类或者实现的接口的所有抽象方法。
- 只能访问final型的局部变量
匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
包装类
Java的设计原则——一切皆对象,但是Java的八种基本数据类型并不符合这种设计思想,它们不是引用数据类型,为了解决这个问题,Java引入了八种基本数据类型的包装类。
基本数据类型 | 包装类 |
---|---|
int | Integer |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
byte | Byte |
short | Short |
long | Long |
以上八种包装类,可以将基本数据类型按照类的形式操作。
以上八种包装类可以分为两大类型:
Number:IntegerShortLongDoubleFloatByte都是Number的子类,表示一个数字。
Object:CharacterBoolean都是object的直接子类
装箱和拆箱
拆箱 | 方法 | 描述 |
---|---|---|
1 | publicbytebyteValue() | 用于Byte->byte |
2 | public abstractdoubledoubleValue() | 用于Double->double |
3 | public abstractfloatfloatValue() | 用于Float->float |
4 | public abstractintintValue() | 用于Integer->int |
5 | public abstractlonglongValue() | 用于Long->long |
6 | publicshortshortValue() | 用于Short->short |
装箱操作:
在JDK1.4之前 ,如果要想装箱,直接使用各个包装类的构造方法即可,例如:
int temp = 10 ;// 基本数据类型
Integer x = new Integer(temp) ;// 将基本数据类型变为包装类
在JDK1.5,Java新增了自动装箱和自动拆箱,而且可以直接通过包装类进行四则运算和自增自减操作。例如:
Float f = 10.3f ;// 自动装箱
float x = f ;// 自动拆箱
System.out.println(f * f) ;// 直接利用包装类完成
System.out.println(x * x) ;// 直接利用包装类完成
字符串转换
使用包装类,我们还可以将字符串变成指定的基本数据类型,在我们接收输入数据的时候使用较多。
Integer类中:
public static int parseInt(String s);
将String字符串转换为int类型
Float类中:
public static float parseFloat(String s);
将String字符串转换为float类型
Boolean类中:
public static boolean parseBoolean(String s)
将String字符串转换为boolean类型
可变参数
我们在一个方法中,可能会定义参数,那么在我们调用这个方法的时候,就需要传入对应的参数。在jdk 1.5 之后提供了新的功能,可以根据我们的需要传入任意个数的参数。
返回值类型 方法名称(数据类型...参数名称){
//参数在方法内部,是以数组的形式来接收的。
}
注意:可变参数只能放在参数列表的最后面