文章目录
C9-C13关于面向对象、封装、继承、多态、接口和异常处理等
比较综合的例子是这篇 11.2修改 ~
https://blog.csdn.net/m0_47681342/article/details/113809753主要参考 Java语言程序设计 梁勇 11E
引用https://hubojing.github.io/
引用https://blog.csdn.net/pt666
引用https://www.it610.com/article/1289214640173162496.htm
C9 对象和类
基本
1、对象(object):现实世界中可以明确标识的实体 例如:一个人、桌子、一笔贷款;
每个对象都有独特的标识,状态和行为。
2、状态(state、property、attribute): 由数据域及其当前值表示的,描述特征。
3、行为(behavior):由方法定义,完成一个动作。
4、类:蓝本,模板,合约。定义数据域及方法。类与对象:配方与苹果派。
定义类和创造对象
类定义对象,对象从类创建
5、构造方法
- 必须和所在类名字相同
- 没有返回值
- 由new操作符调用
6、引用变量
Circle myCircle = new Circle();
7、基本类型变量和引用类型变量区别
- 变量=保存了存储值的内存位置
- 将一个变量引用赋给另一个变量
8、实例变量属于实例,存储在互不相关的内存中。静态变量被同一个类所有实例共享。
- 如果一个方法不依赖于具体的实例,则定义为静态方法。
9、(public、protected、private)可见性修饰符确定一个包私有或访问
10、如果一个类没有定义为公共类,只能在同一个包内访问。
11、数据域封装 因为会被篡改,难以维护
- 所有的数据域声明为私有,构造方法和方法声明为公共。
getter-获取方法,返回数据域的值
setter-给数据域设值
public class Person {
private String name;
private String numbers;
public Person(){
}
public Person(String name, String numbers){
this.name = name;
this.numbers = numbers;
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
... ...
}
12、给方法传递一个对象,是将 对象的引用 传递给方法
this引用
引用自身 或 在构造方法内部调用同一个类的其他构造方法
public void setName(String name){
this.name = name;
//将参数name的值赋给赋给这个类的静态数据name,name被所有静态数据共享
this.add(1,2);//调用本类的add方法,this可忽略
this(5);//调用本类的一个形参的构造函数
C10 面向对象思考
类的抽象和封装
1、类的实现与使用分开,实现的细节被封装并隐藏
2、面向对象 数据+方法对象对象及对象的操作
3、类的关系:关联、聚合、组合、继承
public class employee extends Person{
private String salary;
//关联
private MyDate dateOfEmployment = new MyDate();
public employee(){
}
4、将基本数据类型作为对象处理
int–Integer
double–Double
5、基本类型与包装类型转换
Integer[] intArray = {1,2,3}
StringBuilder StringBuffer
String一旦创建值就确定。
StringBuffer–多任务并发,同步,修改快速
StringBuilder–单线程,不同步,修改更快
public static void changeValue(int a)
{
a = 10;
}
public static void changeValue(String s1)
{
s1 = "def";
}
public static void changeValue(StringBuffer s1)
{
s1.append("def");
}
public static void main(String[] args)
{
int a = 5;
String b = "abc";
StringBuffer c = new StringBuffer("abc");
changeValue(a);
changeValue(b);
changeValue(c);
System.out.println(a);//5
System.out.println(b);//abc
System.out.println(c);//abcdef
}
C11 继承和多态
-
继承:从已经存在的类中定义新类
-
父类和子类(is-a):继承使得定义通用的类,之后继承为一个更特定的类。
-
子类继承父类所有数据域和方法,可直接使用。
-
子类也会继承父类的所有的属性和方法(但不能直接访问private成员)
子类可以通过调用父类的方法来访问父类的私有的成员属性
在同样方法名和参数情况下,本类的方法会比父类的方法优先级高 -
显示调用父类无参构造super
public employee(String salary,MyDate dateOfEmployment, String name, String numbers){
super(name,numbers);
this.salary = salary;
this.dateOfEmployment = dateOfEmployment;
}
- 难点是 何使用继承建模,何时用其他建模?
方法重写&重载
子类需要修改父类中定义的方法的实现。
外壳不变,核心变。也就是说方法名不变,参数不变,具体实现可以改变。
-
在子类中使用一样的签名在父类中定义。
-
仅当实例方法被访问时才能重写
@Override
public String toString(){
return "Student类:姓名为" + super.getName() + " 电话为"
+ super.getNumbers() + " 年级为" + status;
}
-重载:(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
- 每个重载的方法(或者构造函数)都必须有不同的参数类型列表。
object类及toString()方法
- Java中所有类都继承java.lang.Object类,所以,“所有对象都有这个方法”。
- toString()返回描述该对象的字符串,默认返回该对象所属列名。
- 方便输出,以返回一个描述该对象的描述性字符串。
多态
-
类转型:类型可相互转型,但只限制于有继承关系的类
-
子类可转换成父类(从大到小,向上转型),而父类不可转为子类(从小变大,向下转型)
-
父类转为子类有一种情况例外:这个父类本身就是从子类转化而来
Human obj1 = new Man();//OK, Man extends Human
Man obj2 = (Man) obj1;//OK, because obj1 is born from Man class
- 类型转换带来的作用就是多态
- 多种形式 使用父类对象的地方可以使用子类形态
1、对象转换和instance操作符
- 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
- 如果 a instanceof A返回true,则 a instanceof B也返回true,其中,类B是类A的父类。
if(p2 instanceof Woman){
Woman w1=(Woman)p2;
w1.goShopping();
}
2、Arraylist
- 泛型类,具有泛型类型E
- 大小是灵活的,所以无须提前给定大小。而当创建一个数组时,它的大小必须给定。
- 包含许多有用的方法。比如,可以使用contains 方法来测试某个元素是否在列表中。如果使用数组,则需要编写额外代码来实现该方法
// 从数组创建数组列表
String[] array = {"red","green","blue"};
ArrayList<String> list = new ArrayList<>(Arrays.asList(array));
//从数组列表创建对象数组
String[] array1 = new String[list.size()];
list.toArray(array1);
// 数组列表中的元素也可以使用foreach 循环来进行遍历
for (elementType element: arrayList){
// Process the element
}
//example
for (int number: list)
System.out.print(number + " ");
3、protected
想让该类的继承类使用方法,而不想让该类的用户使用。
4、final
一个被final修饰的类和方法不能被继承。被final修饰的数据域是个常数。
- math String都是最终类
C12 异常处理
- 异常是运行时的错误。异常处理使得程序可以处理运行时的错误,并且继续执行。
- 不应该由方法来终止程序,应该由调用者决定
- 异常是方法抛出的,方法的调用者可以捕获以及处理。
- Exception分为RuntimeException程序自身的错误(如5/0,空指针,数组越界)和非RuntimeException外界相关的错误(如打开一个不存在的文件,加载一个不存在的类)。
IOException是非RuntimeException的典型示例。 - 另一种分类方法:
Unchecked Exception:(编译器不会辅助检查的,需要管理员自己管的)异常,包括Error子类和RuntimeException子类。
非RuntimeException的Exception的子类:(编译器会辅助检查的)异常,checked exception。
注意:编译器会检查程序是否为checked exception配置了处理。若没有处理,会报错。
- 异常处理
try-catch-finally:一种保护代码正常运行的机制。
异常结构
try…catch(catch可以有多个,下同)
try…catch…finally
try…finally
try必须有,catch和finally至少要有一个
try:正常业务逻辑代码
catch:当try发生异常,将执行catch代码。若无异常,绕之。
finally:当try或catch执行结束后,必须要执行finally。
try
{
int a = 5/2;
System.out.println(a);
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("1 over");
}
try
{
int a = 5/0;
System.out.println(a);
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("2 over");
}
try
{
int a = 5/0;
System.out.println(a);
}
catch(Exception ex)
{
ex.printStackTrace();
int a = 5/0;
}
finally
{
System.out.println("3 over");
}
3中,第一个异常执行完finally后再执行第二个异常。(catch内部再次发生异常也不影响finally的正常运行。)
进入catch块后,并不会返回到try发生异常的位置,也不会执行后续的catch块,一个异常只能进入一个catch块。
一般将小异常(具体的异常子类,如ArithmeticException)写在前面,大(宽泛)的异常(如Exception)写在末尾。
允许包含:
try{
try-catch-finally结构
}
catch(){
try-catch-finally结构
}
finally{
try-catch-finally结构
}
方法存在可能异常的语句,但不处理,可使用throws来声明异常。
调用带有throws异常(checked exception)的方法,要么处理这些异常,或者再次向外throws,直到main函数为止。
public class ThrowsDemo
{
public static void main(String [] args)
{
try
{
int result = new Test().divide(3,1);
System.out.println("1 result:" + result);
}
catch(ArithmeticException ex)
{
ex.printStackTrace();
}
int result = new Test().divide(3,0);
System.out.println("2 result:" + result);
}
}
class Test
{
//ArithmeticException is a RuntimeException, not checked exception
public int divide(int x, int y) throws ArithmeticException
{
int result = x/y;
return x/y;
}
}
一个方法被覆盖,覆盖它的方法不限抛出相同的异常,或者异常的子类。
如果父类的方法抛出多个异常,那么重写的子类方法必须抛出那些异常的子集,也就是不能抛出新的异常。
Father.java
public class Father{
public void f1() throws ArithmeticException
{
}
}
Son.java
public class Son extends Father{
public void f1() throws Exception//错误
}
自定义异常
- 自定义异常需要继承Exception类或其子类。
继承自Exception,就变成Checked Exception。
继承自RuntimeException,就变成Unchecked Exception。
(非RuntimeException,是Checked Exception,IDE辅助检查;RuntimeException,是Unchecked Exception,IDE不会辅助检查,是程序员自行处理。) - 自定义重点在构造函数
- 调用父类Exception的message构造函数
- 可自定义自己的成员变量
- 在程序中采用throw主动抛出异常
MyException.java
public class MyException extends Exception{
private String returnCode;//异常对应的返回码
private String returnMsg;//异常对应的描述信息
public MyException(){
super();
}
public MyException(String returnMsg){
super(returnMsg);
this.returnMsg = returnMsg;
}
public MyException(String returnCode, String returnMsg){
super(returnMsg);
this.returnCode = returnCode;
this.returnMsg = returnMsg;
}
public String getReturnCode(){
return returnCode;
}
public String getReturnMsg(){
return returnMsg;
}
}
在方法内部程序中,抛出异常采用throw关键字;在方法头部声明中,声明异常采用throws关键字。
MyExceptionTest.java
public class MyExceptionTest {
public static void testException() throws MyException {
throw new MyException("10001", "The reason of myException");
}
public static void main(String[] args) {
//MyExceptionTest.testException();注释1 要报错需注释掉下方代码
try {
MyExceptionTest.testException();
} catch (MyException e) {
e.printStackTrace();
System.out.println("returnCode:" + e.getReturnCode());
System.out.println("returnCode:" + e.getReturnMsg());
}
}
}
注释1:main函数里调用了一个声明MyException异常的方法,但没处理。因为MyException继承Exception,是属于非RuntimeException,也就是Checked Exception,因此编译器会检查到程序没处理而报错。解法:1)采用try-catch-finally结构 2)main函数也throws MyException。
DivideByMinusException.java
public class DivideByMinusException extends Exception {
int divisor;
public DivideByMinusException(String msg, int divisor)
{
super(msg);
this.divisor = divisor;
}
public int getDevisor()
{
return this.getDevisor();
}
}
Student.java
public class Student {
public int divide(int x, int y)
{
return x/y;
}
public static void main(String[] args) throws DivideByMinusException {
Student newton = new Student();
//newton.divide2(5,0);
newton.divide5(5,-2);
}
public int divide2(int x,int y)
{
int result;
try
{
result = x/y;
System.out.println("result is " + result);
}
catch(ArithmeticException ex)
{
System.out.println(ex.getMessage());
return 0;
}
catch(Exception ex)
{
ex.printStackTrace();
return 0;
}
}
public int divide3(int x,int y) throws ArithmeticException//unchecked exception
{
return x/y;
}
public int divide4(int x, int y)
{
// try
// {
// return divide3(x,y);
// }
// catch(ArithmeticException ex)
// {
// ex.printStackTrace();
// return 0;
// }
return divide3(x,y);//尽管divide3报告异常,但divide4无需处理。
//若调用divide5(x,y);就需要做try-catch处理。
}
public int divide5(int x,int y) throws DivideByMinusException
{
try
{
if(y < 0)
{
throw new DivideByMinusException("The divisor is negative", y);
}
return divide3(x,y);
}
catch(ArithmeticException ex)
{
ex.printStackTrace();
return 0;
}
}
}
对于CheckedException,编译器要求调用者处理,要么采用try-catch-finally处理,要么采用throws声明异常。
C13 抽象类和接口
-
抽象类:若方法只有方法名字,形参列表,没有方法体,那所在的类就被定义为抽象类。
-
若一个类暂时有方法未实现,需被定义为抽象类。
-
抽象类可以包含抽象方法,将在具体的子类中实现。
-
一个类继承于抽象类,就不能继承于其他的(抽象)类
-
子类可继承于抽象类,但一定要实现父类们所有abstract的方法,若不能完全实现,子类也必须被定义为抽象类
-
接口:如果类的所有方法都没有实现,这个类就算是接口interface
-
目的是指明相关或不相关对象共同的行为
public interface Animal{
public void eat();
public void move();
}