一、继承 extends
1.继承的格式
继承是java面向对象编程技术的基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,或者子类从父类继承方法,使得子类具有父类相同的行为。
继承的格式:
class 子类 extends 父类{
}
2.子类实例化内存分析
java中只有单继承和多重继承,没有多继承。
子类在创建时,会去找子类的父类,如果有会先在堆里创建一个父类对象,然后创建一个子类对象,并且有一个super 存储父类的地址。子类直接不能操作父类的私有属性,但是可以通过get、set方法来操作。
子类创建多少个就会创建多少个父类对象。
3.super详解
通过super可以访问父类构造方法、父类的属性以及父类的构造方法。
通过super可以调用父类的无参构造方法和有参构造方法,但是通过super调用父类的构造方法需要将super方法写在子类构造方法的第一行。
父类Human类:
/**
* @Author: Mr Bai`s Soda
* @Description:
* @Date Created in 2021-02-23 9:41
* @Modified By:
*/
public class Human {
private String name;
private int age;
public Human() {
}
public Human(String name, int age) {
this.name = name;
this.age = age;
}
/**
* @param
* @Description 人介绍自己的方法
* @Return void
* @Author Mr Bai's Soda
* @Date Created in 2021/2/23 9:47
**/
public void say() {
System.out.println("我是人,我的名字:" + this.name + ",年龄:" + this.age);
}
}
子类Student类:
/**
* @Author: Mr Bai`s Soda
* @Description:
* @Date Created in 2021-02-23 9:42
* @Modified By:
*/
public class Student extends Human {
private String name;
private int age;
/**
* super调用父类的无参构造方法
*/
public Student() {
super();
}
/**
* super调用父类的全参构造方法
*/
public Student(String name, int age) {
super(name, age);
}
/**
* @param
* @Description 学生重写介绍自己的方法
* @Return void
* @Author Mr Bai's Soda
* @Date Created in 2021/2/23 9:58
**/
@Override
public void say() {
//super.say(); 调用父类的say()方法
System.out.println("我是学生,我的名字:" + this.name + ",年龄:" + this.age);
}
}
4.重载(overload)和重写(override)
(1)重写的规则
1)参数列表必须与被重写的方法相同
2)返回值类型必须与被重写的方法相同
3)访问权限不能比父类中被重写的方法的访问权限更低
4)父类的成员方法只能被它的子类重写
5)声明为static和private的方法不能被重写但是能够被再次声明
(2)java中重写override和重载overload的区别
1)重写是发生在子父类中,重载是发生在一个类中;
2)参数列表限制不同,重载必须不同,重写必须相同;
3)重载与返回值类型无关,重写返回值类型必须一致;
4)重载与访问权限无关,重写子类的方法权限必须不能小于父类的权限
5)异常处理,重载与异常无关,重写异常的范围可以更小,但是不能抛出新的异常。
5.final关键字
final关键字用于修饰属性、变量(变量和属性被修饰后成为常量,无法再次赋值,局部变量如果定义时未赋值,那么只可赋值一次,如果是成员属性声明时必须赋值)、类或方法。
final 修饰的类不可以被继承,修饰的方法不能被子类重写。
全局常量可以用 public static final 来声明,命名时由多个单词组成,单词之间用"_"隔开,单词中所有字母大写。
二、抽象类
1.概念:
用abstract关键字修饰的类,一个抽象类可以没有抽象方法,但是抽象方法必须写在抽象类或者接口中。
格式:
abstract class 类名{
public abstract void 方法名();//只声明不实现
}
2.性质
抽象类不能被实例化,不能用关键字new完成。一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)必须重写抽象类中的全部方法。
抽象类里也可以有不抽象的部分。
3.抽象类的常见问题:
1)抽象类不能被final声明,因为final是不能有子类的。
2)抽象类可以有构造方法,而且子类对象实例化的时候流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默认是无参构造方法),之后再调用子类自己的构造方法。
3)抽象类和普通类的区别:
抽象类必须用public或protected修饰,默认缺省为public
抽象类不可以使用new关键字创建对象,但是在子类创建对象时,抽象父类会被JVM实例化。
如果子类继承抽象类,必须实现父类所有的抽象方法,如果有一个未实现的方法,子类也必须定义为抽象类。
三、接口(interface)
1.概念
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么就可以定义为接口。要建立面向接口编程思想:接口是定义与实现的分离。建议写程序时,先写接口。
2.格式
interface 接口名称{
全局常量;
抽象方法;
}
3.优点
降低程序的耦合性、易于程序的扩展、有利于程序的维护。
4.简写
因为接口本身都是由全局常量和抽象方法组成的,所以定义常量时可以省略public static final ,省略后如 int INDEX = 5(全局常量声明必须赋值);抽象方法可以省略 public abstract,省略后如 void print(); 。
5.接口的实现
格式:
class 子类 implements 父接口1,父接口2....{
}
如果一个类既要实现接口,又要继承抽象类,可以按照如下格式:
class 子类 extends 父类 implements 父接口1,父接口2...{
}
6.接口的继承:
接口允许多继承,因为接口都是抽象部分,不存在具体实现,如:
interface C extends A,B{
}
如果一个接口想要使用,必须依靠子类。子类如果不是抽象类要实现抽象类中的所有方法。
7.抽象类和接口的区别:
1)抽象类要被子类继承,接口要被子类实现;
2)接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法;
3)接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;
4)抽象类使用继承来使用,无法多继承;接口使用实现来使用,可以多实现;
5)抽象类中可以包含static方法,但是接口中不允许(因为静态方法不能被子类重写,因此接口中不能声明静态方法)
6)接口不能有构造方法,但是抽象类可以有。(子类创建时,接口不会创建实例)
四、多态
1.概念
多态就是对象的多种表现形式(体现形态)
2.多态的体现
对象的多态:子类就是父类的一种形态,比如Student类是Person类的一种形态
方法的多态:重载是一个类中方法的多态性体现
重写是子父类中方法的多太性体现
3.多态的使用
对象类型的转换,类似于基本数据类型的转换。
1)向上转型:将子类实例变为父类实例,父类对象具体指向的内容是它的一种子形态
父类 父类对象 = 子类实例;
Person person = new Student();
2)向下转型:将父类实例变为子类实例
子类 子类对象 = (子类类型)父类对象;//加子类类型进行强转
Student student = (Student) person;
五、instanceof
1.作用
判断某个对象是否是指定类的实例,可以使用instanceof关键字,
2.格式
实例化对象 instanceof 类 //此操作返回boolean类型的数据
stu1 instanceof Student;
六、Object类概述
1.概念
Object是所有类的父类,如果一个类没有明确的继承某一个具体的类,则默认继承Object类。
Object可以接收任意的引用数据类型。
2.Object类中的方法
1)toString方法(public String toString):
返回对象的字符串表现形式,建议所有子类覆盖此方法,通过文字描述类的更详细的信息。
2)equals方法
指示某个其他对象是否“等于”此对象,比较的结果是boolean类型,比较的是内存的地址,重写时不要违反equals的五个特性。
重写根据业务进行调整,如果没有特殊的需求,所有的属性都要比较(可以快捷键创建)。
七、内部类(应用极少)
在java中,在一个类的里面在定义一个类,这样的类称为内部类。内部类分为成员、局部、匿名、静态内部类。
1.成员内部类
最普通的内部类,定义位于另一个类的内部。可以无条件访问外部类所有成员属性和成员方法(包括private和静态成员),但是当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏,默认访问内部类的同名成员(访问最近的),如果要访问外部的,用 外部类.this.成员变量 或者 外部类.this.成员方法。不能通过new来创建内部类实例。
外部使用成员内部类:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner();
2.局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,和成员内部类的区别在于局部内部类的访问权限仅限于方法内或者该作用域内。相当于方法里的一个局部变量,不能带修饰符。
3.匿名内部类
匿名内部类属于局部内部类的一种,没有名字,只使用一次。
格式:
new 父类构造器(参数列表)|实现接口(){
//匿名内部类的类体部分
}
注意事项:必须继承一个类或者实现一个借口,两者不可兼得;不能定义构造函数;不能存在任何静态成员变量或静态方法;匿名内部类属于局部内部类的一种,所以局部内部类的限制对匿名内部类同样生效;匿名内部类不能抽象,而且必须实现继承的类或者接口的所有抽象方法;只能访问final型的局部变量(局部内部类在编译时会另外生成一个class文件,对final局部变量进行了备份,为了保证变量值绝对一致,系统对规则进行了限制,保证final的值不被更改)。
4.静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。不需要依赖外部类对象的,和静态成员属性有点类似,并且不能使用外部类的非static成员变量或者方法。
八、包装类
java提供了八种基本数据类型的包装类,解决了一切皆对象的问题。其中Integer、Short、Long、Double、Float、Byte都是Number的子类,表示一个数字;Character、Boolean都是Object的直接子类。
1.装箱和拆箱操作
装箱是把基本数据类型的值包装成一个类,拆箱与之相反。
1)手动装箱和拆箱:
Integer i = new Integer(200);
int a = i.intValue();
2)自动装箱和拆箱:
Float f = 10.3f;
float x = f;
包装类可以将一个字符串变为指定的基本数据类型,使用如 parseInt(String s)、parseFloat(String s)、parseBoolean(String s)等方法。
九、可变参数
一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是JDK1.5后,可以根据需要传入任意个数的参数。
格式:
返回值类型 方法名称(数据类型 参数名称){
//参数在方法内部,以数组的形式来接收
}
如 public static int sum(int... nums){
int n = 0;
for ( int i = 0;i < nums.length;i++){
n += nums[i];
}
return n;
}
可变参数只能出现在参数列表的最后。
十、递归
递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或者间接调用自身方法的算法。