java 面向对象高级
十二 继承
继承:
继承是Java面向对象编程技术的一块基石,因为他允许创建分等级层次的类。
继承就是子类继承的特征和行为,使子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法是的子类具有父类相同的行为。
格式:
class 父类{
}
class 子类 extends 父类{
}
简单的来说:就是一个类将另一个类当作父亲,他继承父亲的所有属性并且可以调用,我们来拿代码演示一下。
首先我们创建一个Person类再创建一个Student类并且继承Person类:
然后再main方法中通过Student类来调用Person类的属性和方法:
继承的限制:
Java中只有单继承,多重继承,没有多继承。
十三 super关键字
通过super,可以访问父类的构造方法(调用super构造方法的代码,必须写在子类构造方法的第一行)
通过super,可以访问父类的属性
通过super,可以访问父类的方法
首先我们创建一个Person类作为父类
创建一个Student子类:
main方法:
打印结果:
十四 方法的重写(override)
通俗的来讲,我们在父类创建一个方法,但是子类觉得这个方法不能描述子类的行为,这样在子类中又写同样的方法,我们叫做方法的重写。
重写规则(override)规则:
1、参数列表必须完全与被重写方法的相同。
2、返回类型必须完全与被重写方法的返回类型相同。
3、访问权限不能比父类中被重写方法的访问权限更低。
例如:如果父类的一个方法被声明为public,那么子类中重写的方法就不能声明为protected。
4、父类的成员方法只能被它的子类重写。
5、声明static和private的方法不能被重写,但是能够被再次声明。
面试题:
Java中重写(Override)与重载(Overload)的区别:
1、发生的位置:
重载:一个类中
重写:子父类中
2、参数列表限制:
重载:必须不同的
重写:必须相同
3、返回值类型:
重载:与返回值类型无关
重写:必须相同的
4、访问权限:
重载:与访问权限无关
重写:子的访问权限不能小于父的访问权限
5、异常处理:
重载:与异常无关
重写:异常范围可以更小,但是不能抛出新的异常
十五 final关键字
final用于修饰属性、变量:
变量变成了常量,无法对其再一次进行赋值。
final修饰的局部变量,只能赋值一次(可以先声明后赋值)
final修饰的成员属性,必须声明时赋值。
全局常量(public static final)
在任何地方通过类名调用直接进行访问。
全局常量命名规范:
由一个或多个单词组成,单词之间必须使用下划线隔开,单词中的所有字母大写。
例如:public static final SQL_INSERT;
final用于修饰类:
final修饰的类不可以被继承
final用于修饰方法:
final修饰的方法不能被子类重写
十六 抽象类
概念:
1、一个类如果存在不确定的方法,我们称为抽象类
2、抽象类必须使用abstract class声明
3、一个类可以没有抽象方法。
4、抽象方法必须写在抽象类或者接口中。
格式:
abstract class 类名{
}
抽象方法:
只声明未实现的方法称为抽象方法,(未实现指的是没有“{}”方法体),抽象方法必须使用abstract关键字声明。
格式:
abstract class 类名{
public abstract void 方法名(); //抽象方法只声明而未实现
}
接下来我们拿代码来演示一下:
创建一个Human抽象类:
创建一个Student1类并且继承Human类:
创建一个Teacher类并且继承Human类:
在main方法中调用
打印结果:
在抽象类使用的几个原则:
1、抽象类本身不能之间进行实例化(创建对象)操作的,即:不能使用关键字new完成。
2、一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则必须重写抽象类中的全部方法。
抽象类和普通类的区别:
1、抽象类必须用public或protected修饰(如果为private修饰,那么子类无法继承,也就是无法实现其抽象方法)。默认缺省为public
2、抽象类不可以使用new关键字创建对象,但是子类创建对象时,抽象父类也会被JVM实例化。
3、如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有为实现的抽象方法,那么子类也必须定义为abstract类。
面试题:
1、抽象类能否使用final声明?
不能,因为final修饰的类是不能有子类的,而抽象类必须有;子类才有意义,所以不能。
2、抽象类能否有构造方法?
能,而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。
十七 接口
概念:
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口。
定义格式:
interface 接口名称{
全局常量 ;
抽象方法 ;
}
接口编程的优点:
1、 降低程序的耦合性
2、 易于程序的扩展
3、 有利于程序的维护
全局常量和抽象方法的简写:
因为接口本身都是由全局常量和抽象方法组成 , 所以接口中的成员定义可以简写:
1、全局常量编写时, 可以省略public static final 关键字,
例如: public static final String INFO = “内容” ;
简写后: String INFO = “内容” ;
2、抽象方法编写时, 可以省略 public abstract 关键字,
例如: public abstract void print() ;
简写后: void print() ;
接口实现implement
接口可以多实现:
格式:
class 子类 implements 父接口1,父接口2…{
}
以上的代码称为接口的实现。那么如果一个类即要实现接口,又要继承抽象类的话,则按照以下的格式编写即可:
class 子类 extends 父类 implements 父接口1,父接口2…{
}
我们用代码来演示一遍:
首先创建一个Human类接口:
在创建一个Student类来实现Human:
在main方法中调用:
打印内容为:
接口的继承
接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承,例如:
interface C extends A,B{
}
注意:
如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法。
接口和抽象类的区别:
1、抽象类要被子类继承,接口要被类实现。
2、接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
3、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
4、抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
5、抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
6、接口不能有构造方法,但是抽象类可以有
十八 多态
概念:
多态:就是对象的多种表现形式。(多种体现形态)
多态的体现:
对象的多态性,从概念上非常好理解,在类中有子类和父类之分,子类就是父类的一种形态 ,对象多态性就从此而来。
ps:方法的重载和写也是多态的一种,不过是方法的多态(相同方法名的多种形态)。
重载:一个类中方法的多态性体现
重写:子父类中方法的多态性体现。
接下来我们用代码来体现一下:
创建一个Human接口:
创建一个Student1类来实现Human接口:
创建一个Teacher类来实现Human接口:
在main方法中体现多态:
打印输出:
多态的使用:对象的类型转换
类似于基本数据类型的转换:
· 向上转型:将子类实例变为父类实例
格式:父类 父类对象 = 子类实例 ;
· 向下转型:将父类实例变为子类实例
格式:子类 子类对象 = (子类)父类实例 ;
我们通过代码来演示一下在多态中对象类型的转换:
程序同上面的一样,我们改一下main方法:
输出结果
同为子类不能相互转型 我们看代码:
打印结果为:
多态的实际应用:
打印结果为:十九instanceof
作用:
判断某个对象是否是指定类的实例,则可以使用instanceof关键字
格式:
实例化对象instanceof类 //此操作返回的是boolean类型的数据
接下来我们看代码操作:
二十 object类
概念:
Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object类。
例如我们定义一个类:
public class Person{
}
其实他被使用时 是这样的:
public class Person extends Object{
}
Object的多态
使用Object可以接受任意的引用数据类型
二十一 toString
建议重写Object中的toString方法。
此方法的作用:
返回对象的字符串表示形式。 Object的toString方法, 返回对象的内存地址。
我们用代码演示一遍:
首先创建一个Human对象:
通过main方法来使用tostring方法:
我们在Human类中重写Object中的toString方法:
再在main方法中打印:
二十二 equals
建议重写Object中的equals(Object obj)方法。
此方法的作用:
指示某个其他对象是否“等于”此对象。
equals方法重写时的五个特性:
1、自反性:对于任何非空的参考值x ,x.equals(x)应该返回true 。
2、对称性:对于任何非空引用值x和y ,x.equals(y)应该返回true当且仅当y.equals(x)回报true。
3、传递性:对于任何非空引用值x ,y和z ,如果x.equals(y)回报true个y.equals(z)回报true,然后 x.equals(z)应该返回true。
4、一致性:对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false,前提是未修改对象上的equals比较中使用的信息。
5、非空性:对于任何非空的参考值x ,x.equals(null)应该返回false 。
我们用代码演示一遍:
我们发现将h1和h2作比较,明明h1和h2传入的参数一样,为什么返回的的是false;因为没重写之前的equals比较的是h1和h2的内存地址,接下来我们尝试重写equals方法后继续比较h1和h2。
我们再来看一下打印的结果:
二十三包装类
概述:
在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就完全不符合于这种设计思 想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型 的包装类。以上的八种包装类,可以将基本数据类型按照类的形式进行操作。
但是,以上的八种包装类也是分为两种大的类型的:
· Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
· Object:Character、Boolean都是Object的直接子类。
装箱和拆箱操作:
将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。
将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作,
装箱操作:
在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) ; // 直接利用包装类完成
使用包装类还有一个优点是:
将一个字符串变为指定的基本数据类型,这种情况一般在接受输入数据上使用较多。
下面我们用代码演示一遍:
肯定有好多人认为最后的输出结果为101,我们看一个i接收的不是一个数值,而是一个字符串。所以“i+1”不是指的是两数之和,而指的是拼接。那我们接下来演示一下如何把这个字符串转换成数值:
这下我们看到输出的结果为101,但字符串转换成数值有一个前提,这个字符串必须由数字组成的。
二十五 可变参数
一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根 据需要自动传入任意个数的参数。
语法:
返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意:
可变参数只能出现在参数列表的最后。
我们在程序上演示一遍: