1、多态

多态的条件是:有继承或实现,有方法覆盖或实现,父类引用(接口)指向子类对象
多态是同一个行为具有多个不同表现形式或形态的能力。

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
图片1.png

多态的优点
1. 可替换性
2. 灵活性
3. 简化性

多态存在的三个必要条件

  • 继承
  • 重写/覆盖
  • 父类引用指向子类对象:Parent p = new Child();

    2、接口和抽象类的区别?

  1. 接口描述了方法的特征,不给出实现,一方面解决java的单继承问题,实现了强大的可接插性
  2. 抽象类提供了部分实现,抽象类是不能实例化的,抽象类的存在主要是可以把公共的代码移植到抽象类中
  3. 面向接口编程,而不要面向具体编程(面向抽象编程,而不要面向具体编程)
  4. 优先选择接口(因为继承抽象类后,此类将无法再继承,所以会丧失此类的灵活性)

3、类之间的关系

1、继承关系

类和类之间的继承关系及接口与接口之间的继承
1647159400(1).png
1647159429(1).png

2、实现关系

类对接口的实现
1647159466(1).png

3、关联关系

类与类之间的连接,一个类可以知道另一个类的属性和方法,在java语言中使用实例变量体现
1647159523(1).png
1647159581(1).png

4、Object类

  • Object类是所有Java类的根基类
  • 如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object类

如:

  1. public class User {
  2. ………..
  3. }
  4. 相当于
  5. public class User extends Object {
  6. ………..
  7. }

1、toString()(一般都需要重写)

返回该对象的字符串表示。通常toString 方法会返回一个“以文本方式表示”此对象的字符串,Object 类的 toString 方法返回一个字符串,该字符串由类名加标记@和此对象哈希码的无符号十六进制表示组成,Object类toString源代码如下:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())

在进行String与其它类型数据的连接操作时,如:
System.out.println(student);,它自动调用该对象的 toString()方法
【代码示例】

  1. public class ToStringTest01 {
  2. public static void main(String[] args) {
  3. int i = 100;
  4. System.out.println(100);
  5. Person person = new Person();
  6. person.id = 200;
  7. person.name = "张三";
  8. //会输出Person@757aef
  9. //因为它调用了Object中的toString方法
  10. //输出的格式不友好,无法看懂
  11. System.out.println(person);
  12. }
  13. }
  14. //class Person extends Object { //和以下写法等同
  15. class Person{
  16. int id;
  17. String name;
  18. }

【代码示例】,覆盖Person中的toString方法

  1. public class ToStringTest02 {
  2. public static void main(String[] args) {
  3. Person person = new Person();
  4. person.id = 200;
  5. person.name = "张三";
  6. //System.out.println(person.toString());
  7. //输出结果为:{id=200, name=张三}
  8. //因为println方法没有带Person参数的
  9. //而Person是Object,所以他会调用println(Object x)方法
  10. //这样就是产生object对其子类Person的指向,而在Person中
  11. //覆盖了父类Object的toString方法,所以运行时会动态绑定
  12. //Person中的toString方法,所以将会按照我们的需求进行输出
  13. System.out.println(person);
  14. }
  15. }
  16. //class Person extends Object { //和以下写法等同
  17. class Person{
  18. int id;
  19. String name;
  20. public String toString() {
  21. return "{id=" + id + ", name=" + name + "}";
  22. }
  23. }

2、finalize

垃圾回收器(Garbage Collection),也叫GC,垃圾回收器主要有以下特点:

  • 当对象不再被程序使用时,垃圾回收器将会将其回收(当没有任何外界引用使用的时候,GC会在某个时间段进行回收)
  • 垃圾回收是在后台运行的,我们无法命令垃圾回收器马上回收资源,但是我们可以告诉他,尽快回收资源(System.gc和Runtime.getRuntime().gc())
  • 垃圾回收器在回收某个对象的时候,首先会调用该对象的finalize方法
  • GC主要针对堆内存
  • 单例模式的缺点【因为不能被垃圾回收,会一直存在直到项目停止】

当垃圾收集器将要收集某个垃圾对象时将会调用finalize,建议不要使用此方法,因为此方法的运行时间不确定,如果执行此方法出现错误,程序不会报告,仍然继续运行

  1. public class FinalizeTest01 {
  2. public static void main(String[] args) {
  3. Person person = new Person();
  4. person.id = 1000;
  5. person.name = "张三";
  6. //将person设置为null表示,person不再执行堆中的对象
  7. //那么此时堆中的对象就是垃圾对象
  8. //垃圾收集(GC)就会收集此对象
  9. //GC不会马上收集,收集时间不确定
  10. //但是我们可以告诉GC,马上来收集垃圾,但也不确定,会马上来
  11. //也许不会来
  12. person = null;
  13. //通知垃圾收集器,来收集垃圾
  14. System.gc();
  15. /*
  16. try {
  17. Thread.sleep(5000);
  18. }catch(Exception e) {
  19. }
  20. */
  21. }
  22. }
  23. class Person{
  24. int id;
  25. String name;
  26. //此方法垃圾收集器会调用
  27. public void finalize() throws Throwable {
  28. System.out.println("Person.finalize()");
  29. }
  30. }

注意以下写法

  1. public class FinalizeTest02 {
  2. public static void main(String[] args) {
  3. method1();
  4. }
  5. private static void method1() {
  6. Person person = new Person();
  7. person.id = 1000;
  8. person.name = "张三";
  9. //这种写法没有多大的意义,
  10. //执行完成方法,所有的局部变量的生命周期全部结束
  11. //所以堆区中的对象就变成垃圾了(因为没有引用指向对象了)
  12. //person = null;
  13. }
  14. }
  15. class Person{
  16. int id;
  17. String name;
  18. public void finalize() throws Throwable {
  19. System.out.println("Person.finalize()");
  20. }
  21. }

3、==与equals方法

等号“==”
等号可以比较基本类型和引用类型,等号比较的是值,特别是比较引用类型,比较的是引用的内存地址

  1. public class EqualsTest01 {
  2. public static void main(String[] args) {
  3. int a = 100;
  4. int b = 100;
  5. //可以成功比较
  6. //采用等号比较基本它比较的就是具体的值
  7. System.out.println((a == b)?"a==b":"a!=b");
  8. Person p1 = new Person();
  9. p1.id = 1001;
  10. p1.name = "张三";
  11. Person p2 = new Person();
  12. p2.id = 1001;
  13. p2.name="张三";
  14. //输出为p1!=p2
  15. //采用等号比较引用类型比较的是引用类型的地址(地址也是值)
  16. //这个是不符合我们的比较需求的
  17. //我们比较的应该是对象的具体属性,如:id相等,或id和name相等
  18. System.out.println((p1 == p2)?"p1==p2":"p1!=p2");
  19. Person p3 = p1;
  20. //输出为p1==p3
  21. //因为p1和p3指向的是一个对象,所以地址一样
  22. //所以采用等号比较引用类型比较的是地址
  23. System.out.println((p1 == p3)?"p1==p3":"p1!=p3");
  24. String s1 = "abc";
  25. String s2 = "abc";
  26. //输出s1==s2
  27. System.out.println((s1==s2)?"s1==s2":"s11=s2");
  28. }
  29. }
  30. class Person{
  31. int id;
  32. String name;
  33. }

1647159995(1).png

采用equals比较两个对象是否相等

  1. public class EqualsTest02 {
  2. public static void main(String[] args) {
  3. String s1 = "abc";
  4. String s2 = "abc";
  5. //输出s1==s2
  6. System.out.println((s1==s2)?"s1==s2":"s1=s2");
  7. String s3 = new String("abc");
  8. String s4 = new String("abc");
  9. System.out.println((s3==s4)?"s3==s4":"s3!=s4");
  10. //输出s3等于s4,所以确定string的equals比较的是具体的内容
  11. System.out.println(s3.equals(s4)? "s3等于s4": "s3不等于s4");
  12. Person p1 = new Person();
  13. p1.id = 1001;
  14. p1.name = "张三";
  15. Person p2 = new Person();
  16. p2.id = 1001;
  17. p2.name="张三";
  18. //输出:p1不等于p2
  19. //因为它默认调用的是Object的equals方法
  20. //而Object的equals方法默认比较的就是地址,Object的equals方法代码如下:
  21. // public boolean equals(Object obj) {
  22. // return (this == obj);
  23. // }
  24. //如果不准备调用父类的equals方法,那么必须覆盖父类的equals方法行为
  25. System.out.println(p1.equals(p2)? "p1等于p2": "p1不等于p2");
  26. }
  27. }
  28. class Person{
  29. int id;
  30. String name;
  31. }

在进一步完善

  1. public class EqualsTest03 {
  2. public static void main(String[] args) {
  3. Person p1 = new Person();
  4. p1.id = 1001;
  5. p1.name = "张三";
  6. Person p2 = new Person();
  7. p2.id = 1001;
  8. p2.name="张三";
  9. System.out.println(p1.equals(p2)? "p1等于p2": "p1不等于p2");
  10. }
  11. }
  12. class Person{
  13. int id;
  14. String name;
  15. //覆盖父类的方法
  16. //加入我们自己的比较规则
  17. public boolean equals(Object obj) {
  18. if (this == obj) {
  19. return true;
  20. }
  21. //确定比较类型为person
  22. //同一类型,才具有可比性
  23. if (obj instanceof Person) {
  24. //强制转换,必须实现知道该类型是什么
  25. Person p = (Person)obj;
  26. //如果id相等就认为相等
  27. if (this.id == p.id) {
  28. return true;
  29. }
  30. }
  31. return false;
  32. }
  33. }

以上输出完全正确,因为执行了我们自定义的equals方法,按照我们的规则进行比较的,注意instanceof的使用,注意强制转换的概念。将父类转换成子类叫做“向下转型(造型)”,向下造型是不安全的。“向上转型(造型)”是安全,子类转换成父类,如:将Student转成Person,如Dog转成动物

5、包和import

1、包

包其实就是目录,特别是项目比较大,java文件特别多的情况下,我们应该分目录管理,在java中称为分包管理,包名称通常采用小写
包—三大作用
1、区分相同名字的类
2、当类很多时,可以很好的管理类
3、控制访问范围

  1. /*
  2. 1、包最好采用小写字母
  3. 2、包的命名应该有规则,不能重复,一般采用公司网站逆序,
  4. 如:cn.test.exam.项目名称.模块名称
  5. cn.test.exam
  6. */
  7. //package必须放到 所有语句的第一行,注释除外
  8. package cn.test.exam;
  9. public class PackageTest01 {
  10. public static void main(String[] args) {
  11. System.out.println("Hello Package!!!");
  12. }
  13. }

运行出现类不能找到错误,提示给的很明显,如cn.imjcoder.exam.PackageTest01类不能找到,因为我们加入了包,所以我们的class文件必须放到和包一样的目录里才可以,这就是采用包来管理类,也就是采用目录来管理类,建立目录com/imjcoder/exam,采用java PackageTest01执行,同样出现上面的错误,如果采用了包在执行该类时必须加入完整的包名称,正确的执行方式为java cn.imjcoder.exam.PackageTest01

正确执行通过。
另外还有一点需要注意:必须在最外层包采用java来执行,也就是classpath必须设置在chapter03目录上,以chapter03目录为起点开始找我们的class文件

2、import

如何使用包下的class文件

  1. package cn.exam;
  2. //采用import引入需要使用的类
  3. //import cn.test.exam.model.User;
  4. //import cn.test.exam.model.Student;
  5. //import cn.test.exam.model.Employee;
  6. //可以采用 * 通配符引入包下的所有类
  7. //此种方式不明确,但简单
  8. import cn.exam.model.*;
  9. //package必须放到 所有语句的第一行,注释除外
  10. //package cn.imjcoder.exam;
  11. public class PackageTest02 {
  12. public static void main(String[] args) {
  13. User user = new User();
  14. user.setUserId(10000);
  15. user.setUserName("张三");
  16. System.out.println("user.id=" + user.getUserId());
  17. System.out.println("user.name=" + user.getUserName());
  18. }
  19. }

如果都在同一个包下就不需要import引入了,以上的示例都没有包,可以理解为都在同一个包下,在实际开发过程中不应该这样做,必须建立包

3、JDK常用开发包

  1. java.lang,此包Java语言标准包,使用此包中的内容无需import引入
  2. java.sql,提供了JDBC接口类
  3. java.util,提供了常用工具类
  4. java.io,提供了各种输入输出流

4、Junit扩展

6、访问控制权限

java访问级别修饰符主要包括:private protected、public和default,可以限定其他类对该类、属性和方法的使用权限,

修饰符 类的内部 同一个包里 子类 任何地方
private Y N N N
default Y Y N N
protected Y Y Y N
public Y Y Y Y

注意以上对类的修饰只有:public和default,内部类除外

1、private

【示例代码】

  1. public class PrivateTest01 {
  2. public static void main(String[] args) {
  3. A a = new A();
  4. //不能访问,private声明的变量或方法,只能在同一个类中使用
  5. System.out.println(a.id);
  6. }
  7. }
  8. class A {
  9. private int id;
  10. }

2、protected

【代码实例】,在同一个包下,建立类ProtectedTest01、A,并建立B继承A

  1. public class ProtectedTest01 {
  2. public static void main(String[] args) {
  3. A a = new A();
  4. a.method1();
  5. A b = new B();
  6. b.method1();
  7. B b1 = new B();
  8. b1.method3();
  9. }
  10. }
  11. class A {
  12. //采用protected声明的变量或方法只有子类或同一个包下的类可以调用
  13. protected int id = 100;
  14. public void method1() {
  15. System.out.println(id);
  16. }
  17. protected void method2() {
  18. System.out.println("A.method2()");
  19. }
  20. }
  21. class B extends A {
  22. public void method1() {
  23. //可以正确调用
  24. //因为和A在同一个包下
  25. System.out.println(id);
  26. }
  27. public void method3() {
  28. //可以正确调用
  29. method2();
  30. }
  31. }

【代码示例】,在test1下建立类C1,在test2下建立ProtectedTest02和C2类

  1. package test2;
  2. import test1.C1;
  3. public class ProtectedTest02 {
  4. public static void main(String[] args) {
  5. new C2().method2();
  6. }
  7. }
  8. class C2 extends C1 {
  9. public void method2() {
  10. //可以调用,主要原因C2是C1的子类
  11. //所以可以访问protected声明的变量
  12. System.out.println(id);
  13. method1();
  14. }
  15. }
  16. class C3 {
  17. public void method3() {
  18. //不能在其他类中访问protected声明的方法或变量
  19. //new C1().method1();
  20. }
  21. }

3、default

如果class不采用public修饰,那么此时的class,只能被该包下的类访问,其他包下无法访问

  1. import test3.D;
  2. public class DefaultTest01 {
  3. public static void main(String[] args) {
  4. D d = new D();
  5. d.method1();
  6. //不能访问,只有在一个类中或在同一个包下可以访问
  7. //在子类中也不能访问
  8. d.method2();
  9. }
  10. }

7、内部类

在一个类的内部定义的类,称为内部类
内部类主要分类:

  • 成员内部类
  • 局部内部类
  • 静态内部类
  • 匿名内部类

    1、成员内部类

  • 创建实例内部类,外部类的实例必须已经创建

  • 实例内部类会持有外部类的引用
  • 实例内部不能定义static成员,只能定义实例成员 ```java public class InnerClassTest01 {

    private int a;

    private int b;

    InnerClassTest01(int a, int b) {

    1. this.a = a;
    2. this.b = b;

    }

    //内部类可以使用private和protected修饰 private class Inner1 {

    1. int i1 = 0;
    2. int i2 = 1;
    3. int i3 = a;
    4. int i4 = b;
    5. //实例内部类不能采用static声明
    6. //static int i5 = 20;

    }

    public static void main(String[] args) {

    1. InnerClassTest01.Inner1 inner1 = new InnerClassTest01(100, 200).new Inner1();
    2. System.out.println(inner1.i1);
    3. System.out.println(inner1.i2);
    4. System.out.println(inner1.i3);
    5. System.out.println(inner1.i4);

    }
    }

  1. <a name="tqXXb"></a>
  2. ### **2、静态内部类**
  3. - 静态内部类不会持有外部的类的引用,创建时可以不用创建外部类
  4. - 静态内部类可以访问外部的静态变量,如果访问外部类的成员变量必须通过外部类的实例访问
  5. 【示例代码】
  6. ```java
  7. public class InnerClassTest02 {
  8. static int a = 200;
  9. int b = 300;
  10. static class Inner2 {
  11. //在静态内部类中可以定义实例变量
  12. int i1 = 10;
  13. int i2 = 20;
  14. //可以定义静态变量
  15. static int i3 = 100;
  16. //可以直接使用外部类的静态变量
  17. static int i4 = a;
  18. //不能直接引用外部类的实例变量
  19. //int i5 = b;
  20. //采用外部类的引用可以取得成员变量的值
  21. int i5 = new InnerClassTest02().b;
  22. }
  23. public static void main(String[] args) {
  24. InnerClassTest02.Inner2 inner = new InnerClassTest02.Inner2();
  25. System.out.println(inner.i1);
  26. }
  27. }

3、局部内部类

局部内部类是在方法中定义的,它只能在当前方法中使用。和局部变量的作用一样
局部内部类和实例内部类一致,不能包含静态成员

  1. public class InnerClassTest03 {
  2. private int a = 100;
  3. //局部变量,在内部类中使用必须采用final修饰
  4. public void method1(final int temp) {
  5. class Inner3 {
  6. int i1 = 10;
  7. //可以访问外部类的成员变量
  8. int i2 = a;
  9. int i3 = temp;
  10. }
  11. //使用内部类
  12. Inner3 inner3 = new Inner3();
  13. System.out.println(inner3.i1);
  14. System.out.println(inner3.i3);
  15. }
  16. public static void main(String[] args) {
  17. InnerClassTest03 innerClassTest03 = new InnerClassTest03();
  18. innerClassTest03.method1(300);
  19. }
  20. }

4、匿名内部类

是一种特殊的内部类,该类没有名字

  • 没有使用匿名类 ```java public class InnerClassTest04 {

    public static void main(String[] args) {

    1. MyInterface myInterface = new MyInterfaceImpl();
    2. myInterface.add();

    }
    }

interface MyInterface {

  1. public void add();

}

class MyInterfaceImpl implements MyInterface {

  1. public void add() {
  2. System.out.println("-------add------");
  3. }

}

  1. - 使用匿名类
  2. ```java
  3. public class InnerClassTest05 {
  4. public static void main(String[] args) {
  5. /*
  6. MyInterface myInterface = new MyInterface() {
  7. public void add() {
  8. System.out.println("-------add------");
  9. }
  10. };
  11. myInterface.add();
  12. */
  13. /*
  14. MyInterface myInterface = new MyInterfaceImpl();
  15. InnerClassTest05 innerClassTest05 = new InnerClassTest05();
  16. innerClassTest05.method1(myInterface);
  17. */
  18. InnerClassTest05 innerClassTest05 = new InnerClassTest05();
  19. innerClassTest05.method1(new MyInterface() {
  20. public void add() {
  21. System.out.println("-------add------");
  22. }
  23. });
  24. }
  25. private void method1(MyInterface myInterface) {
  26. myInterface.add();
  27. }
  28. }
  29. interface MyInterface {
  30. public void add();
  31. }
  32. /*
  33. class MyInterfaceImpl implements MyInterface {
  34. public void add() {
  35. System.out.println("-------add------");
  36. }
  37. }
  38. */