面向对象特征二:继承性
一、继承性的好处
① 减少代码的冗余,提高了代码的复用性
② 便于功能的扩展
③为多态性的使用,提供了前提
二、继承性的格式:class A entends B{}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
2.1 体现:一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有的结构:属性、方法
特别的:父类中声明为private的属性或方法,子类继承父类后中,仍然继承了父类中私有的结构,
受封装性的影响,只是因为封装性的影响,是的子类不能直接调用父类的结构而已。
2.2 子类继承父类以后,还可以声明自己特有的属性或方法 ,实现功能的扩展
三、java中继承的规定
1.一个类可以被多个子类继承
2.java中类的单继承性:一个类只能有一个父类
3.子父类是相对的概念,
4.子类直接继承的父类,称为直接父类,简洁继承的父类称为间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中所有的属性和方法
四、如果没有显示的声明一个类的父类,则此类继承于java.lang.object类,所有的java类出本身,
都直接或间接的继承于java.lang.object,所有Java类具有的java.lang.object类中声明的结构
person类:
package com.atguigu.java; public class Person { String name; private int age; public Person() { } public Person(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println("吃饭"); } public void sleep() { System.out.println("睡觉"); } public void setAge(int age) { this.age = age; } public int getAge() { return age; } }
student类
package com.atguigu.java; public class Student extends Person{ String major; public Student() { } public Student(String name,int age,String major) { this.name = name; setAge(age); this.major = major; } public void study() { System.out.println("学习"); } }
test类
package com.atguigu.java; public class ExtendsTest { public static void main(String[] args) { Person p = new Person(); p.eat(); Student s = new Student(); s.name = "TOM"; s.sleep(); s.setAge(10); int b = s.getAge(); System.out.println("b="+b); } }
重写的规定(override/overwrite):
1.子类继承父类以后,可以对父类中的同名同参的方法,进行覆盖操作。
2.应用:重写以后,当创建子类对象后,通过子类对象调用父类中的同名同参的方法,实际执行的是子类重写父类中的方法。
* 方法的声明: 权限修饰符 返回值类型 方法名(形参列表)throws 异常类型{
* 方法体
* }
* ① 子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和参数列表相同
* ②子类重写的方法权限修饰符不小于父类方法的权限修饰符
* >特殊情况:子类方法不能重写父类中声明为private权限的方法
* ③返回值类型:
* >父类被重写的方法的返回值类型是void或基本数据类型,则子类重写方法的返回值类型也只能是void或对应的基本数据类型
* >父类被重写的方法的返回值是A类型,则子类重写方法的返回值类型可以是A类型或者是A类型的子类
* ④子类重写的方法抛出的异常不大于父类被重写的方法抛出的异常类型
* 子类和父类中同名同参数的方法要么都声明为非static(考虑重写),要么都声明为static的。
Person类:
package com.atguigu.java1; public class Person { String name; int age; public Person() { } public Person(String name,int age) { this.name = name; this.age = age; } public void eat() { System.out.println("吃饭"); } public void walk(int distance) { System.out.println("走路"+distance); } }
Studet类
package com.atguigu.java1; public class Student extends Person{ String major; public Student(){ } public Student(String major){ this.major = major; } public void study() { System.out.println("专业是"+major); } public void eat() { System.out.println("学生应该多吃有营养的食物"); } }
Test类
package com.atguigu.java1; public class PersonTest { public static void main(String[] args) { Student s = new Student("计算机"); s.eat(); s.walk(10); s.study(); } }
* 关键字super的使用:
* 1.super理解为:父类的
* 2.super可用来调用:属性、方法、构造器
*
* 3.super的使用;
* 3.1 在子类的方法或构造器中,通过“super。属性”或“super.方法”的方式,显示调用父类中声明的属性或方法。但是通常情况下,省略:“super.”
* 3.2 特殊情况:当子类和父类中定义了同名属性时,想在子类中调用父类中声明的属性,必须使用“super。属性”的方式,表明调用的是父类中声明的属性。
* 3.3特殊情况:当子类重写父类中的方法以后,想在子类方法中调用父类被重写的方法时,使用“super.方法”调用
*
* 4.super调用构造器
* 4.1在子类的构造器中显示使用“super(形参列表)”的方式,调用父类声明的指定的构造器
* 4.2 "super(参考列表)"的使用,必须声明在子类构造器的首行
* 4.3 "super(形参列表)"或"this(形参列表)"只能二选一,不能同时出现,默认是“super()”
* 子类对象实例化的全过程
* 1.从结果上看:子类继承父类以后,就获取了父类中声明的属性和方法。
* 创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。
*
* 2.从过程上看:通过子类的构造器创建子类对象时,一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,
* 直到调用java.lang.object类中空参的构造器为止。正因为贾在国所有父类中的结构,
* 才可以看到内存中有父类中的结构,子类对象才可以进行调用。
* 多态性
* 1.父类的引用指向子类的对象
* 2.多态的使用
* 有了对象的多态性以后,在编译期,只能调用父类中声明的方法,在运行期,执行的是子类重写父类的方法
* 3.多态使用前提:①有继承
* ②有重写
* ③父类引用指向子类对象
*4.多态性只适于方法,不适于属性
*
*instanceof操作符
* 1.多态性相当于向上转型
* 2.使用强转时可能出现ClassCastException的异常,
* 3.instanceof关键字的使用 :
* a instanceof A:判断对象a是否是类A的实例,如果是,返回true,否则返回false
*
* java.lang.object类
1.object类是所有java类的根父类
2.object类中的功能(方法:equals、toString、getClass、hashCode、clone、finalize…)就具有通用性
==和equals比较:
package com.atguigu.java3; /* * ==与equals()区别 * * ==:运算符 * 1.可以使用在基本数据类型和引用数据类型变量中 * 2.如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等 * 如果比较的是引用数据类型变量:比较两个对象的地址值是否相等 * * equals()方法的使用 * 1.是一个方法,而非运算符,只能适用于引用数据类型 * 2.Object类中equals()的定义: * public boolean equals(Object obj){ * return this == obj; * } * 说明:Object类中定义的equals()和==的作用是相同的 * * 3.像String、Date、File、包装类等都重写了Object中的equals()方法。 * 重写以后,比较的是“实体内容”是否相同,而非对象的地址值是否相同 * 4.通常情况下,自定义类使用equals()的话,也是比较实体内容是否相等,需要对Object类中的equals()进行重写 * * 5.自动生成equals方法:source---generate hashCode() and equals() */ public class EqualsTest { public static void main(String[] args) { Customer cust1 = new Customer("tom",21); Customer cust2 = new Customer("tom",21); System.out.println(cust1.equals(cust2)); } }
package com.atguigu.java3; public class Customer { private String name; private int age; public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } public Customer() { } public Customer(String name,int age) { super(); this.name = name; this.age = age; } //手动写: // public boolean equals(Object obj) { // if(this == obj) { // return true; // } // if(obj instanceof Customer) { // Customer cust = (Customer) obj; // //比较两个对象的每个属性是否都相同 // if(this.age == cust.age && this.name.equals(cust.name)) { // return true; // }else{ // return false; // } // } // return false; // } //自动生成 @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Customer other = (Customer) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
toString类
package com.atguigu.java3; /* * Object中toString()的使用 * 1.当输出一个对象的引用时,实际上就是调用当前对象的toString()方法 * 2.Object类中toString()定义: * public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } * 3.像 String、Date、file、包装类等都重写了object类中的toString方法, * 使得在调用对象的toString()时,返回“实体内容”信息 * 4.自定义类,也可以重写toString()方法,调用此方法时,返回对象的“实体内容” */ public class ToStringTest { public static void main(String[] args) { Customer cust1 = new Customer("tom",21); System.out.println(cust1.toString());//com.atguigu.java3.Customer@311d617d System.out.println(cust1);//com.atguigu.java3.Customer@311d617d String str = new String("mm"); System.out.println(str); } }
单元测试
package com.atguigu.java4; import java.sql.Date; import org.junit.Test; /* * java中的JUnit单元测试 * 1.步骤:选中当前工程---右键选择:build path --- add libraries -Junit 4--下一步 * 2.创建一个java类,进行单元测试 * 此时的java类要求:①此类是public的 * ②此类提供公共的无参的构造器 * 3.在此类中声明单元测试方法 * 此时的单元测试方法:方法的权限是public,没有返回值,没有形参 * 4.此单元测试方法上需要声明注释:@Test,并在单元测试类中导入import org.junit.Test; * 5.声明好单元测试方法以后,就可以在方法体内测试相关代码 * 6.写完代码以后,左键双击单元方法名,右键:run as -- JUnit Test */ public class JunitTest { int number = 10; @Test public void testEquals() { String s1 = "mm"; String s2 = "mm"; System.out.println(s1.equals(s2)); //ClassCastException :类型转换异常 // Object obj = new String("gg"); // Date date = (Date) obj; System.out.println(number); } }
* 包装类
* 基本数据类型 包装类
* byte Byte
* short Short
* int Integer
* long Long
* float Float
* double Double
此及以上:父类:Number,Number类继承于Object
* boolean Boolean
* char Character
*
*基本数据类型、包装类、String三者相互转换
* 1.基本数据类型---》包装类:调用对应包装类的构造器
*
* boolean 包装类在忽略大小写的情况下,只要内容是true ,返回 true,其他内容返回false
*
* 2.包装类--->基本数据类型:调用包装类的xxxValue()
* 自动装箱和自动拆箱
* 1.自动装箱
* Integer num1 = 10;
* Integer in1 = num1;
*
* 2.自动拆箱
* int num2 = in1;
*
* 基本数据类型、包装类---->String类型:调用String重载的valueOf(Xxx xxx);
* String类型--->基本数据类型、包装类:调用包装类的parseXxx(String s)方法
Integer内部定义了IntegerCache结构,IntegerCache中定义了Integer[],保存了-128~127范围内的整数,使用自动装箱的方式,给Integer赋值范围在-128~127范围内时,可以直接使用数组中的元素,不用再去new了。目的:提高效率
package com.atguigu.java4; import org.junit.Test; public class WrapperTest { //String类型--->基本数据类型、包装类:调用包装类的parseXxx() @Test public void test5() { String str = "123"; int in1 = Integer.parseInt(str); } //基本数据类型、包装类---->String类型:调用String重载的valueOf(Xxx xxx) @Test public void test4() { //方法1:运算符连接 int num= 10; String str1 = num+""; //方法2:调用String的valueOf(Xxx xxx) float f1 = 12.3f; String str2 = String.valueOf(f1); } /* * JDK 5.0新特性:自动装箱和拆箱 */ @Test public void test3() { //自动装箱 int num2 = 10; Integer i1 = num2; //自动拆箱 int num3 = i1; } //包装类----->基本数据类型:调用包装类的xxxValue() @Test public void test2() { Integer i1 = new Integer(12); int in1 = i1.intValue(); System.out.println(in1+1); } //基本数据类型------>包装类:调用包装类的构造器 @Test public void test1() { int num1 = 10; Integer i1 = new Integer(num1); System.out.println(i1.toString()); Integer i2 = new Integer(123); System.out.println(i2.toString()); Boolean b1 = new Boolean(true); Boolean b2 = new Boolean("true"); Boolean b3 = new Boolean("true123"); System.out.println(b3);//false Order order = new Order(); System.out.println(order.isMale);//false System.out.println(order.isFemale);//null } } class Order{ boolean isMale; Boolean isFemale; }
* 关键字static
* 1.static:静态的
* 2.static可以用来修饰:属性、方法、代码块、内部类
* 3.使用static修饰属性:静态变量(或类变量)
* 3.1属性,按是否使用static修饰,分为:静态属性和非静态属性(实例变量)
* 实例变量:创建类的多个对象,每个对象都独立的拥有一套类中的非静态属性,当修改其中一个对象中的
* 非静态属性时,不会导致其他对象中同样的属性值的修改
* 静态变量:创建类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致
* 其他对象调用此静态变量时,是修改过了的。
* 3.2 static 修饰属性的其他说明:
* ①静态变量随着类的加载而加载,可以通过“类.静态变量”的方式进行调用
* ②静态变量的加载要早于对象的创建
* ③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。
* ④ 类变量 实例变量
* 类调用 可以 不可
* 对象调用 可以 可以
* 3.3 静态属性举例:System.out; Math.PI;
*
*
* 4.使用static修饰方法:静态方法
* ①随着类的加载而加载,可以通过“类.静态方法”调用
* ②静态方法中,只能调用静态的方法或属性
* 非静态方法中,既可以调用非静态的方法和属性,也可以调用静态方法和属性
*
* 5.static注意点:
* 在静态方法内,不能使用this、super关键字
*
* 6.开发中,如何确定一个属性是否要声明为static的
* 》属性是可以被多个对象所共享的,不会随着对象的不同而不同
* 》类中的常量也常常声明为static
*
* 开发中,如何确定一个方法是否需要声明为static的
* 》操作静态属性的方法,一般设置成static的
* 》工具类中的方法,习惯上声明为static的,如Math、Arrays、Collections
*
*
* 单例设计模式:
* 1.采用一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例
* 2.如何实现 :饿汉式 懒汉式
*
* 一、饿汉式
* ①私有化类的构造器
* ②内部创建类的对象,要求此对象也必须声明为静态的
* ③提供公共的静态的方法,返回类的对象
*
* public class SingletonTest { * public static void main(String[] args) { * Bank bank1 = Bank.getBank(); * Bank bank2 = Bank.getBank(); * System.out.println(bank1 == bank2);//ture * } * } * class Bank{ * //1.私有化构造器 * private Bank() { * } * //2.内部创建类的对象 * //4.要求此对象也必须声明为静态的 * private static Bank instance = new Bank(); * //3.提供公共的静态方法,返回类的对象 * public static Bank getBank() { * return instance; * } * }
* 二、懒汉式:
* ①私有化类的构造器
* ②声明当前类对象,没有初始化
* ③声明public、static的返回当前类对象的方法
* public class SingletonTest2 { * public static void main(String[] args) { * Order order1 = Order.getOrder(); * Order order2 = Order.getOrder(); * System.out.println(order1 == order2); * } * } * class Order{ * //1.私有化类的构造器 * private Order() { * } * //2.声明当前类对象,没有初始化 * private static Order instance = null; * //3.声明public、static的返回当前类对象的方法 * public static Order getOrder() { * if(instance == null) { * instance = new Order(); * } * return instance; * } * }
*3.区分饿汉式和懒汉式
* 饿汉式:坏处:创建对象,对象加载时间过长。
* 好处:线程安全
* 懒汉式:好处:延迟对象的创建。
* 坏处:目前写法 线程不安全
代码块
package com.atguigu.java5; /* * 代码块(初始化块) * 1.代码块的作用:用来初始化类或者对象 * 2.代码块如果修饰的话,只能使用static修饰 * 3.分类:静态代码块和非静态代码块 * 4.静态代码块 * >内部可以有输出语句 * >随着类的加载而执行,只执行一次 * >作用:初始化类的信息 * >如果一个类中定义了多个静态饭吗快,则按照声明的先后顺序执行 * >静态代码块的执行,要优先于非静态代码块的执行 * 5.非静态代码块 * >内部可以有输出语句 * >随着对象的创建而执行,每创建一个对象,就执行一次非静态代码块 * >作用:可以在创建对象时,对对象的属性等进行初始化 * * 对属性可以赋值的位置: * ①默认初始化 * ②显示初始化/代码块中赋值 * ③构造器中初始化 * ④有了对象以后,可以通过“对象.属性”或“对象.方法”的方式,进行方式 * * * 总结:由父及子,静态先行 */ public class BlockTest { public static void main(String[] args) { String descs = Person.desc; Person p1 = new Person(); System.out.println(p1.age); Person.info(); } } class Person{ //属性 String name; int age; static String desc = "我是一个人"; //构造器 public Person() { } public Person(String name,int age) { this.name = name; this.age = age; } //静态代码块 static{ System.out.println("hello,static block"); info(); } //非静态代码块 { System.out.println("hello, block"); this.age = 1; } //方法 public void eat() { System.out.println("吃饭"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } public static void info() { System.out.println("我是一个快乐的人"); } }
final
package com.atguigu.java5; /* * final:最终的 * 1.final可以修饰的结构:类、方法、变量 * * 2.final 用来修饰一个类:此类就不能被其他类所继承 比如:String类、System类、StringBuffer类等 * * 3.final 用来修饰方法 :表明此方法不能被重写 * 比如:Object类中getClass() (获取当前对象所属于的类) * * 4.final 用来修饰变量:此时的“变量”就称为是一个常量 * 4.1 final修饰属性:可以考虑赋值的位置:显示初始化、代码块中赋值、构造器中初始化 * 4.2 final修饰局部变量: * 尤其是是使用final修饰形参时,表明此形参是一个参量。当调用此方法时,给常量形参赋值一个实参 * 一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。 * * static final 用来修饰属性:全局常量 */ public class FinalTest { final int width =10; //final int width; The blank final field width may not have been initialized final int LEFT; { LEFT = 1; } public void dowidth() { //The final field FinalTest.width cannot be assigned //width = 20; } public static void main(String[] args) { } } /* final class FinalA{ } //The type B cannot subclass the final class FinalA class B extends FinalA{ } */ /* class AA{ public final void show() { } } //Cannot override the final method from AA class BB extends AA{ public void show() { } } */
* abstract关键字的使用
package com.atguigu.java5; /* * abstract关键字的使用 * 1.abstract:抽象的 * 2.abstract可以修饰类、方法 * * 3.abstract修饰类:抽象类 * abstract class A{ * * } * 》此类不能实例化(不能创建对象) * 》抽象类中一定有构造器,便于子类实例化时调用(涉及,子类对象实例化的全过程) * 》开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作 * * 4.abstract修饰方法 * public abstract void xX(); * 》只有方法的声明,没有方法体 * 》包含抽象方法的类一定是抽象类,反之,抽象类中可以没有抽象方法 * 》若子类重写了父类中的所有的抽象方法后,此子类方可实例化 * 若在子类没有重写父类中多有的抽象方法,则此子类也是抽象类,需要使用abstract修饰 * * 5.abstract使用上的注意点: * 1.abstract不能用来修饰:属性、构造器等结构 * 2.abstract不能用来修饰私有方法(私有方法不能被子类重写)、静态方法、final的方法、final类 */ public class AbstractTest { public static void main(String[] args) { // Cannot instantiate the type Person:一旦Person类抽象了,就不可实例化 // Person p1 = new Person(); // p1.eat(); } } abstract class Person{ String name; int age; public Person() { } public Person(String name,int age) { this.name= name; this.age = age; } public abstract void eat(); public void walk() { System.out.println("人走路"); } } //针对抽象方法,子类中重写抽象方法 或者依旧使子类为抽象类 class Student extends Person{ public Student(String name,int age) { super(name,age); } public void eat() { } }
抽象类练习
package com.atguigu.exe2; /* * 定义一个employee类,包含: * private成员变量name,number,birthday,其中birthday为MyDate类的对象; * abstract方法earings() * toString()方法输出对象的name,number和birthday */ public abstract class Exployee { private String name; private int number; private MyDate birthday; public Exployee(String name, int number, MyDate birthday) { super(); this.name = name; this.number = number; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } public abstract double earings(); @Override public String toString() { return "name=" + name + ", number=" + number + ", birthday=" + birthday.toDateString() ; } }
package com.atguigu.exe2; /* * MyDate类包含 * pravate成员变量year,month,day; * toDateString()方法返回对应的字符串:xxxx年xx月xx日 */ public class MyDate { private int year; private int month; private int day; public MyDate(int year, int month, int day) { super(); this.year = year; this.month = month; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } public String toDateString() { return this.year+"年"+this.month+"月"+this.day+"日"; } }
package com.atguigu.exe2; /* * 定义SalariedEmployee类继承Employ类 * 实现按月计算工资的员工处理。该类包括:private成员变量monthlySalary * 实现父类的抽象方法earings(),该方法返回monthSalary值 * toString()方法输出员工类型信息及员工的name,number,birthday */ public class SalariedEmployee extends Exployee{ public double monthSalary;//月工资 //子类首先用super()调用父类构造器,但父类中无空参构造器,需要在子类中提供带参构造器 public SalariedEmployee(String name, int number, MyDate birthday) { super(name, number, birthday); // TODO Auto-generated constructor stub } public SalariedEmployee(String name, int number, MyDate birthday,double monthSalary) { super(name, number, birthday); this.monthSalary = monthSalary; // TODO Auto-generated constructor stub } public double getMonthSalary() { return monthSalary; } public void setMonthSalary(double monthSalary) { this.monthSalary = monthSalary; } @Override public double earings() { return monthSalary; } public String toString() { return "SalariedEmployee["+super.toString()+"]"; } }
package com.atguigu.exe2; /* * 参照SalariedEmployee类定义HourlyEmployee类,实现按照小时计算工资的员工处理, * private成员变量:wage 和 hour * 实现父类的抽象方法earings(),该方法返回wage*hour * toString()方法输出员工类型信息及员工的name,number,birthday */ public class HourlyEmployee extends Exployee{ private double wage; private double hour; public HourlyEmployee(String name, int number, MyDate birthday) { super(name, number, birthday); } public HourlyEmployee(String name, int number, MyDate birthday,double wage,double hour) { super(name, number, birthday); this.hour = hour; this.wage = wage; } public double earings() { return wage * hour; } public String toString() { return "HourlyEmployee["+super.toString()+"]"; } }
package com.atguigu.exe2; import java.util.Scanner; /* * 定义PayrollSystem类,创建Employee变量数组并初始化,该数组存放各类雇员对象的应用。 * 利用循环结构遍历数组元素,输出各个对象的类型,name,number,birthday,以及该对象的生日 * 当键盘输入本月的月份值时,如果本月是某个Employee对象的生日,还要输出增加工资信息 */ public class PayrollSystem { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入当前的月份:"); int month = scan.nextInt(); Exployee[] emps = new Exployee[2]; emps[0] = new SalariedEmployee("mashen",1002,new MyDate(1992,2,28),10000); emps[1] = new HourlyEmployee("panyusheng",2001,new MyDate(1991,5,6),60,240); for(int i = 0; i< emps.length;i++) { System.out.println(emps[i]); double salary =emps[i].earings(); System.out.println("月工资为"+salary); if(month == emps[i].getBirthday().getMonth()) { System.out.println("生日快乐,奖励100元"); salary +=100; System.out.println("月工资为"+salary); } } } }
接口
package com.atguigu.java; /* * 接口的使用 * 1.接口使用interface来定义 * 2.java语言中,接口和类是并列的两个结构 * * 3.如何定义接口,定义接口中的成员 * 3.1 JDK7及以前:只能定义全局常量和抽象方法 * 》全局常量:public static final 的,但是书写时可以省略 * 》抽象方法:public abstract的 * * 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法,默认方法 * 》静态方法只能通过接口直接调用, * 》默认方法通过实现类的对象进行调用,并且可以重写,调用时,是重写以后的方法 * 》如果子类(实现类)继承了父类和实现的接口中声明了同名同参数的方法,那么 子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法 ----》类优先原则 * 》如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错,---接口冲突 * 必须要在实现类中重写此方法, * 调用父类的同名同参方法:super.方法 * 调用接口中同名同参方法:接口名.super.方法 * * 4.接口中不能定义构造器,意味着接口不可以实例化 * 抽象类也不可能实例化,但是抽象类中具有构造器,提供给子类使用(super) * 5.java开发中,接口通过让类去实现(implements)的方式使用 * 如果实现类重写了接口中的所有抽象方法,则此实现类就可以实例化 * 如果实现类没有重写接口中对所有的抽象方法,则此实现类仍为一个抽象类 * * 6.java类可以实现多个接口--》弥补了类单继承的局限性 * 格式:class AA extends BB implements CC,DD{} * * 7.接口和接口之间可以继承,而且可以多继承 * * 8.接口的具体使用,体现了多态 * 9.接口,实际上可以看做是一种规范 */ public class InterfaceTest { public static void main(String[] args) { System.out.println(Flyable.MAX_SPEED); } } interface Flyable{ public static final int MAX_SPEED = 7900; int MIN_SPEED = 1;//可以省略public static final public abstract void fly(); void stop();//省略public abstract } interface Attackable{ public abstract void attack(); } class Plane implements Flyable{ @Override public void fly() { System.out.println("飞机起飞"); } @Override public void stop() { System.out.println("飞机停止飞行"); } } class Bullet extends Object implements Flyable,Attackable,CC{ @Override public void attack() { } @Override public void fly() { } @Override public void stop() { } @Override public void method() { } @Override public void method1() { } } //************************************************ interface AA{ public abstract void method(); } interface BB{ public abstract void method1(); } interface CC extends AA,BB{ }
接口练习
package com.atgui.exe; /* * interface CompareObject{ * public int compareTo(Object o); * //若返回值是0,代表相等;若返回整数,代表当前对象大;负数代表当前对象小 * } */ public interface CompareObject { public int compareTo(Object o); } package com.atgui.exe; /* * 定义一个Circle类,声明redius属性,提供get,set方法 */ public class Circle { private double redius; public Circle() { } public Circle(double redius) { this.redius = redius; } public void setRedius(double redius) { this.redius = redius; } public double getRedius() { return redius; } } package com.atgui.exe; /* * 定义一个ComparableCircle继承circle并实现ComparableCircle接口 * 在ComparableCircle实现compareTo的实现提,用来比较两个圆的半径 */ public class ComparableCircle extends Circle implements CompareObject{ public ComparableCircle(double redius) { super(redius); } @Override public int compareTo(Object o) { if(this == o) { return 0; } if(o instanceof ComparableCircle) { ComparableCircle c = (ComparableCircle)o; //精度损失,不太合适 //return (int)(this.getRedius() - c.getRedius()); if(this.getRedius()>c.getRedius()) { return 1; }else if(this.getRedius()<c.getRedius()){ return -1; }else { return 0; } }else { //return 0; throw new RuntimeException("传入的数据类型不匹配"); } } } package com.atgui.exe; public class CircleTest { public static void main(String[] args) { ComparableCircle c1 = new ComparableCircle(3.4); ComparableCircle c2 = new ComparableCircle(3.5); ComparableCircle c3 = new ComparableCircle(3.4); int i1 = c2.compareTo(c1); int i2 = c1.compareTo(c3); System.out.println(i1); System.out.println(i2); } }
内部类
package com.atguigu.java1; /*1 * 类的内部成员之五:内部类 * 1.java中允许将一个类A声明在另一个类B中,则类A是内部类,类B称为外部类 * * 2.内部类的分类:成员内部类(静态,非静态) vs 局部内部类(方法内、代码块内、构造器内) * * 3.成员内部类:一方面作为外部类的成员: * 》调用外部类结构 * 》可以用static修饰 * 》可以被4中不同的修饰符修饰 * * 另一方面,作为一个类: * 》类内可以定义属性、方法、构造器 * 》可以被final修饰,表示此类不能被继承,言外之意,不使用final,就可以被继承 * 》可以被abstract修饰,表示此类不能被实例化 * * * 4.内部类关注的问题 * 》1.如何实例化成员内部类的对象 * 创建 静态的成员内部类 * 外部类.内部类 实例名 = new 外部类.内部类(); * * 创建 非静态的成员内部类 * 外部类 外部类实例 = new 外部类(); * 外部类.内部类 内部类实例 = 外部类实例.new 内部类(); * * 》2.如何在成员内部类中区分调用外部类的结构 * 同名参数时, * 调用内部类中的形参:直接 形参名 * 调用内部类中的属性:this.参数名 * 调用外部类中的属性:外部类.this.参数名 */ public class InnerClassTest { } class Person{ String name; int age; public void eat() { System.out.println("人吃饭"); } //静态成员内部类 static class Dog{ String name; int age; public void show() { System.out.println("卡拉是条狗"); } //eat(); 静态的加载,早于非静态的加载 } //非静态内部类 class Bird{ String name; public Bird() { } public void sing() { System.out.println("一致小鸟"); Person.this.eat(); } } public void method() { //局部内部类 class AA{ } } { //局部内部类 class BB{ } } public Person() { //局部内部类 class CC{ } } }
异常
package com.atguigu.java1; /* * Error: * java虚拟机无法解决的严重问题。如:JVM系统内部错误,资源耗尽严重问题。比如StackOverflowError * 一般不编写针对性的代码进行处理 */ public class ErrorTest { public static void main(String[] args) { //1.栈溢出:java.lang.StackOverflowError //main(args); //2.堆溢出:java.lang.OutofMemoryError Integer[] arr = new Integer[1024*1024*1024]; } }
package com.atguigu.java1; import java.sql.Date; import java.util.Scanner; import org.junit.Test; /* * 一、异常的体系结构 * java.lang.Throwable * |------java.lang.Error: 一般不编写针对性的代码进行处理。 * |------java.lang.Exception: 可以进行异常的处理 * |-----编译时异常(checked) * |-----IOException * |------FileNotFoundException * |-----ClassNotFoundException * |-----运行时异常(unchecked) * |-----NullPointerException * |-----ArrayIndexOutOfBoundsException * |-----ClassCastEcception 类型转换异常 * |-----NumberFormatException * |-----InputMismatchException * |-----ArithmeticException * */ public class ExceotionTest { //运行时异常 //NullPointerException @Test public void test1() { int[] arr = null; System.out.println(arr[3]); } //ArrayIndexOutOfBoundsException @Test public void test2() { int[] arr = new int[3]; System.out.println(arr[3]); } //ClassCastEcception @Test public void test3() { //String ster = new Date();编译出错 Object obj = new Date(0); String str = (String)obj; } //NumberFormatException @Test public void test4() { String str = "123"; str = "abc"; int num = Integer.parseInt(str); } //InputMismatchException @Test public void test5() { Scanner scanner = new Scanner(System.in); int score = scanner.nextInt(); System.out.println(score); } //AritheticException @Test public void test6() { int a = 10; int b = 0; System.out.println(a/b); } }
package com.atguigu.java1; import org.junit.Test; /* * 异常处理:抓抛模型 * 过程一:“抛”: 程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象, * 并将此对象抛出。 * 一旦抛出异常以后,其后的代码就不在执行。 * 关于异常对象的产生:① 系统自动生成的异常对象 * ② 手动的生成一个异常对象,并抛出(throw) * * 过程二:“抓”:异常的处理方式:方式① try-catch-finally * 方式② throws * * * 方式① try-catch-finally的使用 * try{ * //可能出现异常的代码 * }catch(异常类型1 变量名1){ * //处理异常方式1 * }catch(异常类型2 变量名2){ * //处理异常方式2 * }catch(异常类型3 变量名3){ * //处理异常方式3 * } * …… * finally{ * //一定会执行的代码 * } * 说明: * 1.finally是可选的 * 2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成对应异常类的对象, * 根据此对象的类型,去catch中进行匹配 * 3.一旦try中的异常对象匹配到某个catch时,就会进入catch中进行异常处理,一旦处理完成,就跳出当前的try-catch结构(没有finally情况下), * 继续执行其后的代码 * 4.catch中的异常类型,如果没有子父类关系,则声明上下无所谓 * 如果满足子父类关系,要求子类一定声明父类上面,否则出错 * 5.常用的异常对象处理的方式: * ①返回String类型的方法:getMessage(); * ②printStacktrace() 打印整个堆栈信息 * 6.在try结构中声明的变量,在出了try结构后,不可在调用(将变量声明初始化在外面) * * 使用try-catch-finally处理编译时异常,使得程序在编译时就不用报错,但是运行时人可能报错 * 相当于使用try-catch-finally将一个编译时可能出现的错误,延迟到运行时出错。 */ public class ExceptionTest1 { @Test public void test1() { String str = "123"; str = "abc"; int num = 0; //int num = Integer.parseInt(str);报错 try { num = Integer.parseInt(str); System.out.println("step-----1"); }catch(NullPointerException e) { System.out.println("出现空指针转换异常。"); //返回String类型 方法getMessage(); System.out.println(e.getMessage()); }catch(NumberFormatException e) { //返回String类型 方法getMessage(); //System.out.println(e.getMessage());//For input string: "abc" //printStackTrace() e.printStackTrace(); }catch(Exception e) { System.out.println("出现异常。"); } System.out.println("step-----2"); } // For input string: "abc" // step-----2 }
package com.atguigu.java1; import org.junit.Test; /* * try-catch-finally中finally的使用 * * 1.finally是可选的 * 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常,try或catch中有retur语句等情况。 * * 3.像数据库连接、输入输出流、网络编程Socket等资源,jvm是不能自动回收的,需要手动进行资源释放的,此时的资源释放,就需要声明在finally中。 * * 4.try-catch-finally结构可以嵌套使用 * * 5.开发中,由于运行时异常比较常见,所以通常不针对运行异常编写try-catch-finally, * 针对编译时异常,一般考虑异常处理 */ public class FinallyTest { @Test public void testMethod() { int num = method(); System.out.println(num); } public int method() { try { int[] arr = new int[3]; System.out.println(arr[3]); return 1; }catch(ArrayIndexOutOfBoundsException e) { //e.printStackTrace(); System.out.println(e.getMessage());//3 return 2;//2 }finally { System.out.println("一定会被执行");//一定会被执行 return 4; } } // 3 // 一定会被执行 // 4 @Test public void test1() { try { int a = 10; int b = 0; System.out.println(a/b); }catch(ArithmeticException e) { e.printStackTrace(); int[] arr = new int[3]; System.out.println(arr[3]); }finally { System.out.println("一定会执行的代码"); } } }
package com.atguigu.java1; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; /* * 异常处理的方式二:throws + 异常类型 * * 1.“throws + 异常类型” 写在方法的声明处,指明此方法执行时,可能会抛出的异常类型, * 一旦当方法体执行时,出现异常,人会在异常代码处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出, * 异常代码后续的代码将不再执行。 * * 2.try-catch-finally :真正的将异常处理掉了 * throws + 异常类型:知识将异常抛给了方法的调用者,并没有将异常处理掉 * * 3.开发中如何选择使用try-catch-finally 还是 throws * 》3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws, * 如果子类有异常,必须使用try-catch-finally方式处理 * 》3.2 执行的方法中,先后调用了另外的几个方法,这几个方法是递进关系执行的,建议该几个方法使用throws的方式进行处理。 * 而执行的方法a可以考虑使用try-catch-finally进行处理 */ public class ExceptionTest2 { public static void main(String[] args) { try { method2(); } catch (IOException e) { e.printStackTrace(); } } public static void method2() throws IOException{ method1(); } public static void method1() throws FileNotFoundException,IOException{ File file = new File("hello.txt"); FileInputStream fis = new FileInputStream(file); int data = fis.read(); while(data!=-1) { System.out.println((char)data); data = fis.read(); } fis.close(); System.out.println("hello, world"); } }
package com.atguigu.java1; /* * 7 */ public class StudentTest { public static void main(String[] args) { try { Student s = new Student(); s.regist(-1001); System.out.println(s.toString()); } catch (Exception e) { e.printStackTrace(); } } } class Student{ private int id; public void regist(int id) throws Exception {//throws 处理异常 if(id>0) { this.id = id; }else { // System.out.println("输入的数据非法"); //手动抛出异常 // throw new RuntimeException("输入的数据非法"); // throw new Exception("输入的数据非法");//生成异常对象 throw new MyException("输入非法的数据"); } } @Override public String toString() { return "Student [id=" + id + "]"; } }
package com.atguigu.java1; /* * 如何自定义异常类 * 1.继承于现有的异常结构:要么继承Exception、要么继承RuntimeException * 2.提供全局常量serialVersionUID * 3.提供重载的构造器 */ public class MyException extends RuntimeException{ static final long serialVersionUID = -7034897193745766939L; public MyException() { } public MyException(String msg) { super(msg); } }