3、 面向对象高阶
3.1、重写(override) 规则:
- 参数列表必须完全与被重写方法的 相同
- 返回类型必须完全与被重写方法的返回类型相同;
- 访问权限不能比父类中被重写的方法的权限低。
如:父类的方法是 public 修饰,则子类重写方法只能是public - 父类的成员方法只能被子类重写
- 声明为static和private 的方法不能被重写,但是能够被再次声明
3.2、重载(Override)与重写(Overload)的区别
- 发生的位置:
- 重写是发生在子父类中
- 重载是发生在一个类中
- 参数列表限制
- 重载 :必须不同
- 重写:必须相同
- 访问权限
- 重载 : 无权限
- 重写:子的重写不能大于父类的方法
- 返回值类型
- 重载:与返回值无关
- 重写:返回值必须一致
- 异常处理
- 重载:与异常无关
- 重写:子类重写的方法不能比父类的异常范围大
3.3、final(最终)
-
final用于修饰属性、变量。
-
变量成为了常量,无法对其再次进行赋值。
-
final修饰的局部变量,只能赋值一次(可以先声明后赋值)
-
final修饰的成员变量,必须在声明时赋值。
-
全局变量( public static final )
-
常量的命名规范:
由一个或者多个单词组成,单词与单词间必须下划线隔开,单词中所有字母大写
如:SQL_INSERT
-
-
final用于修饰类 不能被继承
-
final用于修饰方法 不能被重写
3.4、抽象类
概念:
抽象类必须使用abstract class声明 一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中。
抽象方法:
只声明而未实现的方法称为抽象方法(未实现指的是:没有“{}”方法体),抽象方法必须使用abstract关键字声明。
格式:
abstract class lei{ // 抽象类
public abstract void fangfa() ; //抽象方法,只声明而为实现
}
原则:
- 抽象类本身是不能直接进行实例化的 ,即:不能直接使用关键字new完成
- 一个抽象类必须被子类所继承,被继承的子类必须重写抽象方法的所有抽象方法
常见问题:
-
抽象类能否使用final声明?
不能! 因为final属性修饰的类是不能有子类的,而抽象类必须有子类才有意义。
-
抽象类能否有构造方法?
能!使用情况都是与普通类一样
-
抽象类不可以使用new关键字创建对象, 但是在子类创建对象时, 抽象父类也会被JVM实例化。
3.5、接口
概念:
如果一个类中的全部方法都是抽象类,全部属性都是全局常量 那么此时就可以将这个类定义为一个接口。
定义格式:
interface name {
int a; // 全局变量
public void method(){}; // 抽象方法
}
面向接口编程思想
这种思想:接口是定义(规范,约束) 与实现(名实分离的原则)的分离
优点:
- 降低程序的耦合性
- 易于程序的扩展
- 有利于程序的维护
全局常量和抽象方法的简写
- 全局常量编写时,可以省略 public static final 关键字
如: public static final String INFO = ”内容“;
变为: String INFO = ”内容“ - 抽象方法编写时,可以省略 public abstract 关键字
如: public abstract void print();
简写为: void print();
接口的实现
使用关键字 implements
接口和抽象类区别
- 抽象类是要被子类继承,接口是要被类实现
- 接口只能写抽象方法,而抽象类既能写抽象方法,又能写非抽象方法
- 接口里定义的变量只能是公共静态的常量 ,抽象类中的变量是普通变量
- 抽象类可以定义 static方法 而接口不允许(静态方法不能被子类重写)
- 抽象类使用继承来使用,无法多继承。接口使用实现来使用,可以多实现
- 抽象能有构造方法,而接口不能有。
3.6、多态
多态的应用
person接口
public interface Person {
public void say();
}
Student 实现person接口
public class Student implements Person {
@Override
public void say() {
System.out.println("我是student的say方法");
}
}
Nurse实现person接口
public class Nurse implements Person {
@Override
public void say() {
System.out.println("我是nurse的say方法");
}
}
main
public class Test {
public static void main(String[] args) {
Student student = new Student();
say(student);// 传入student对象
Nurse nurse = new Nurse();// 传入nurse对象
say(nurse);
}
public static void say(Person p) { // 用接口作为参数
p.say();
}
}
结果:
我是student的say方法
我是nurse的方法
3.7、instanceof
作用:
判断某个对象是否是指定类的实例,则可以使用instanceof关键字
格式:
实例化对象 instanceof 类 //return boolean
3.8、Object类
Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object
类。
例如我们定义一个类:
public class Person{
}
其实它被使用时 是这样的:
public class Person extends Object{
}
3.9、toString
建议重写Object中的toString方法。 此方法的作用:返回对象的字符串表示形式。
object的toString方法,返回对象在内存的地址
3.10、equals
建议重写Object中的equals(Object obj)方法
作用:指示某个其他对象是否“等于”此对象。
== : 比较的内存地址
特性:
自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报 true 。
传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前 提是未修改对象上的equals比较中使用的信息。
非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。
3.11、内部类
概念:在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。
3.11.1、 成员内部类
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();
3.11.2、 局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
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修饰符的。
3.11.3、匿名内部类
匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
只能访问final型的局部变量 -1.8 局部变量可以不写final ,经编译后加上了final
3.11.4、静态内部类
3.12、包装类
在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就完全不符合于这种设计思想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题, 引入了八种基本数据类型的包装类。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kYMrNwiT-1626613770570)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1626148712005.png)]
-
Number:
Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。
-
Object:
Character、Boolean都是Object的直接子类
装箱拆箱
以下以Integer和Float为例进行操作
将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。
将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作,
因为所有的数值型的包装类都是Number的子类,Number的类中定义了如下的操作方法,以下的全部方法都是进行拆箱的操作。
装箱操作: 在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
3.13、可变参数
一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根据需要自动传入任意个数的参数。
语法:
返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
注意:
可变参数只能出现在参数列表的最后
/**
* int... nums :表示的是可变参数,调用时可以传递0——n个数字
* 在方法内部,可变参数是以数组作为载体体现
* @param nums
* @return
*/
public static int sum(int... nums) {
int sum = 0;
for(int i = 0 ; i < nums.length ; i++) {
sum += nums[i];
}
return sum;
}
调用
sum(1,2,3)