Java - 面向对象从基础到高级之中级

tech2022-12-28  116

面向对象中级

一、继承

1.概述:

继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。 继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父亲的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

class 父类 { } Class 子类 extends 父类 { }

2.继承的限制:

Java中只有单继承,多重继承,没有多继承。 多继承:C既继承A又继承B,当A和B有相同的方法容易产生错乱。 多重继承:C继承B,B继承A。

3.补充:

当创建子类对象时,内部的流程中会首先先创建父类对象,当父类对象创建完毕后才会创建自己,并且父类对象会作为自己对象的super存在。 继承实际上是子类拥有了父类的地址。 注意:只有public的和protected修饰的父类,子类才能操作。

二、super关键字

如果父类没有无参构造方法,那么子类在继承时就需要明确的通过super来调用,否则会报错。 通过super,可以访问父类的构造方法; 注意:调用super构造方法的代码必须写在子类构造方法的第一行 通过super,可以访问父类的属性; 通过super,可以访问父类的方法。

class Student extends Person { public Student() {//当调用子类的无参构造方法时 //super();//子类的无参构造方法默认会调用父类的无参构造方法 super("无名称",1);//可手动改为调用父类的有参构造方法 } }

三、重写(Override)

1.概述:

1.参数列表必须完全与被重写方法的相同; 2.返回类型必须完全与被重写方法的返回类型相同; 3.访问权限不能比父类被重写的方法的访问权限更低,例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected; 4.父类的成员方法只能被它的子类重写; 5.声明为static和private的方法不能被重写(根本没有继承何来重写一说),但是能够被再次声明。

2.重写与重载的区别:

Java中重写(Override)与重载(Overload)的区别概括来说重写是发生在子父类中的,子重写父方法的操作;而重载发生在一个类里面,一个类里面有多个方法,但是参数列表的长度或者参数列表的类型和类型顺序不同,这时会构成重载。 1.发生的位置: 重载:一个类中 重写:子父类中 2.参数列表限制: 重载:必须不同 重写:必须相同 3.返回值类型: 重载:与返回值类型无关 重写:返回值类型必须一致 4.访问权限: 重载:与访问权限无关 重写:子的方法权限必须不能小于父的方法权限 5.异常处理: 重载:与异常无关 重写:异常范围可以更小,但是不能抛出新的异常

四、final关键字(常量相关)

1.final用于修饰属性、变量:

此时变量成为了常量,无法对其再次进行赋值。 final修饰的局部变量,只能赋值一次(可以先声明后赋值);final修饰的成员属性,必须在声明时赋值。

2.常亮的命名规范:

全局常亮(public static final) 由1个或多个单词组成,单词与单词之间必须使用下划线隔开,单词中所有字母大写。 例如:SQL_INSERT

3.final用于修饰类:

final修饰的类不可以被继承

4.final用于修饰方法:

final修饰的方法不能被子类重写

五、包装类

1.概述:

在Java中有一个设计的原则“一切皆对象”,那么这样一来Java中的一些基本的数据类型,就完全不符合于这种设计思想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型的包装类。 以上的八种包装类,可以将基本数据类型按照类的形式进行操作。 但是,以上的八种包装类也是分为两种大的类型的: Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字。 Object:Character、Boolean都是Object的直接子类。

2.装箱和拆箱操作:

将一个基本数据类型变为包装类,那么这样的操作称为装箱操作。 将一个包装类变为一个基本数据类型,这样的操作称为拆箱操作。 在JDK1.5,Java新增了自动装箱和自动拆箱,而且可以直接通过包装类进行四则运算和自增自减操作。例如:

Integer j = 200; // 自动装箱 int b = j; // 自动拆箱

3.字符串转换:

使用包装类还有一个很优秀的地方在于:可以将一个字符串变为指定的基本数据类型,此点一般在接收输入数据上使用较多。 在Integer类中提供了以下的操作方法:

public static int parseInt(String s); //将String变为int型数据 //示例 String text = input.nextLine(); int num = Integer.parseInt(text);//包装类,String转换为int

在Float类中提供了以下的操作方法:

public static float parseFloat(String s); //将String变为Float

在Boolean 类中提供了以下操作方法:

public static boolean parseBoolean(String s); //将String变为boolean

六、可变参数

一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但是在JDK 1.5之后提供了新的功能,可以根据需要自动传入任意个数的参数。 在方法的内部,可变参数以数组作为载体体现。 语法:

返回值类型 方法名称(数据类型... 参数名称) { //参数在方法内部,以数组的形式来接收 } //示例 //int... nums:表示的是可变参数,调用时可以传递0-n个数字 public static int sum(int... nums) { int n = 0; for(int i=0;i<nums.length;i++) { n+=nums[i]; } return n; }

注意:可变参数只能出现在参数列表的最后(当传入多种参数时)。

public static void sum(String x,int... y) { }

七、递归

递归,在数学与计算机科学中,是指在方法的定义中使用方法自身。也就是说,递归算法是一种直接或者间接调用自身方法的算法。

public int menu() { System.out.println("请选择操作模式:"); System.out.println("1.管理员"); System.out.println("2.普通用户"); System.out.println("0.退出"); String text = input.nextLine(); int num = Integer.parseInt(text);//包装类,String转换为int if (num < 0 || num > 2) { System.out.println("选择有误,请重新输入!"); return menu();//递归,自己调用自己 } return num; }

但是,A调用B,A就要等待B执行完才会继续执行,B调用C,B就要等待C执行完才会继续执行,就会出现一大堆的方法一直在重复的等待,最终导致内存越占用越大,造成程序崩溃。因此,在解决实际问题时,能用循环就不要用递归,当使用递归时一定要确保这个递归不会执行太多次,造成程序崩溃。 再来看一个实例,使用递归实现5的阶乘:

public static int fact(int n) { if(n == 1) { return 1; } else { return n * fact(n-1); } }

这时,只要在main方法中打印fact(5),就可以实现5的阶乘。 如果你没有看懂这段代码为什么能实现阶乘,那么你可以往下看: 首先fact(5)打算return 5 * fact(4),但是由于fact(4)的存在,它会等待并让fact(4)先执行 fact(4)打算return 4 * fact(3),但是由于fact(3)的存在,它会等待并让fact(3)先执行 fact(3)打算return 3 * fact(2),但是由于fact(2)的存在,它会等待并让fact(2)先执行 fact(2)打算return 2 * fact(1),但是由于fact(1)的存在,它会等待并让fact(1)先执行 fact(1)会return 1,然后fact(1)执行完毕,把值返回给fact(2) fact(2)继续执行,return 2 * fact(1)即2,fact(2)执行完毕,把值返回给fact(3) fact(3)继续执行,return 3 * fact(2)即6,fact(3)执行完毕,把值返回给fact(4) fact(4)继续执行,return 4 * fact(3)即24,fact(4)执行完毕,把值返回给fact(5) fact(5)继续执行,return 5 * fact(4)即120,fact(5)执行完毕,把值返回给main方法并打印出去。 到这里相信你对递归已经有了一定的理解。

最新回复(0)