面向对象

面向对象思想

类的关系

关联

关联是一种描述两个类之间行为的一般二元关系。

关联中的每个类可以指定一个数字或一个数字区间,表示该关联涉及类中的多少个对象。

在 Java 代码中,关联可以用数据域和方法进行实现,一个类中的方法包含另一个类的参数。

下面的代码是关联的例子。储户在银行开账户是储户类 Depositor 和银行类 Bank 之间的关联。每个储户可以在多个银行开设账户,每个银行也可以有多个储户在该银行开设账户。

DepositorBankclass Depositor {private List<Bank> bankList;public Depositor() {bankList = new ArrayList<Bank>();}public void addBank(Bank account) {bankList.add(account);}}

聚集和组合

聚集是一种特殊的关联形式,表示两个对象之间的所属关系。聚集模拟具有(has-a)关系。

所有者对象称为聚集对象,对应的类称为聚集类;从属对象称为被聚集对象,对应的类称为被聚集类。

一个对象可以被几个聚集对象所拥有。如果一个对象被一个聚集对象所专有,该对象和聚集对象之间的关系就称为组合。

下面的代码是聚集和组合的例子。司机类 Driver 是聚集类,汽车类 Car 和身份证类 IDCard 是被聚集类。每个司机驾驶一辆汽车,并拥有一张身份证。由于一辆汽车可以被多个司机驾驶,因此 Driver 和 Car 之间的关系是聚集关系。由于一张身份证只能被一个人拥有,因此 Driver 和 IDCard 之间的关系是组合关系。

DriverCarIDCardclass Driver {private Car car;private IDCard idCard;
}

依赖

依赖指两个类之间一个类使用另一个类的关系,前者称为客户(client),后者称为供应方(supplier)。

在 Java 代码中,实现依赖的方式是,客户类中的方法包含供应方类的参数。

下面的代码是依赖的例子。Java 自带的抽象类 Calendar 包含方法 setTime,该方法包含一个 Date 类型的参数,此处 Calendar 是客户类,Date 是供应方类。

Calendarpublic abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {public final void setTime(Date date) {setTimeInMillis(date.getTime());}
}

继承

继承模拟是(is-a)关系。

强是(strong is-a)关系描述两个类之间的直接继承关系,弱是(weak is-a)关系描述一个类具有某些属性。

强是关系可以用类的继承表示,弱是关系可以用接口表示。

类的设计原则

内聚性

同一个类/模块的所有操作应该有高度关联性,支持共同的目标,只负责一项任务,即单一责任原则,称为高内聚。

不同类/模块之间的关联程度应该尽量低,对一个类/模块的修改应该尽量减少对其他类/模块的影响,称为低耦合。

封装性

类中的数据域应该使用 private 修饰符隐藏其可见性,避免从外部直接访问数据域。

如果需要从外部读取数据域的值,则提供读取器方法。如果需要从外部修改数据域的值,提供设置器方法。

如果一个方法只在类的内部使用,则应该对该方法使用 private 修饰符,避免从外部调用该方法。

实例和静态

依赖于类的具体实例的数据域和方法应声明为实例数据域和实例方法,反之应声明为静态数据域和静态方法。

如果一个数据域被所有实例共享,该数据域应声明为静态数据域。如果一个方法不依赖于具体实例,该方法应声明为静态方法。

继承和聚集

继承模拟是(is-a)关系,聚集模拟具有(has-a)关系。应考虑两个类之间的关系为是关系还是具有关系,决定使用继承或聚集。

this关键字

用法:

(1)this可以修饰属性:

总结:当属性名字和形参发生重名的时候,或者 属性名字 和局部变量重名的时候,都会发生就近原则,所以如果我要是直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候如果我想要表示属性的话,在前面要加上:this.修饰

如果不发生重名问题的话,实际上你要是访问属性也可以省略this.

package com.fyz;public class Demo {public  int age;public String name;public Demo(int age1, String name) {age = age1;//形参和属性没重名,可以省略thisthis.name = name;//重名不可省略}public void test(){int age=10;System.out.println("局部:age"+age);//直接使用名字就是指离得近的局部变量System.out.println("属性:age"+this.age);//获取属性要加this区分,加上指代属性}public static void main(String[] args) {Demo demo=new Demo(20,"fyz");demo.test();}
}输出结果
局部:age10
属性:age20

(2)this修饰方法:

总结:在同一个类中,方法可以互相调用,this.可以省略不写。

public class Demo {public  int age;public String name;public Demo(int age1, String name) {age = age1;this.name = name;}public void test(){int age=10;System.out.println("局部age"+age);System.out.println("属性age"+this.age);test2();//总结:在同一个类中,方法可以互相调用,this.可以省略不写this.test2();//总结:在同一个类中,方法可以互相调用,this.可以省略不写}public void test2(){System.out.println("test2");}public static void main(String[] args) {Demo demo=new Demo(20,"fyz");demo.test();}
}

(3)this可以修饰构造器:

总结:同一个类中的构造器可以相互用this调用,注意:this修饰构造器必须放在第一行

  1. public class Person {//属性int age;String name;double height;//空构造器public Person() {}//有参构造器public Person(int age, String name, double height) {this(age, name);//调用 public Person(int age, String name)this.height = height;}public Person(int age, String name) {this(age);//调用 public Person(int age)this.name = name;}public Person(int age) {this.age = age;}
    }
    

构造方法

定义

构造方法是一种特殊的方法,调用构造方法可以创建新对象

构造方法可以执行任何操作,在实际的应用中一般用于初始化操作,例如初始化对象的数据域

构造方法可以被重载

使用new操作符来调用构造方法,进而创建对象

默认构造方法

类可以不显性声明构造方法。此时类中隐性声明了一个方法体为空的没有参数的构造方法,称为默认构造方法。只有当类中没有显性声明任何构造方法时,才会有默认构造方法。

构造方法与普通方法的区别

构造方法必须和所属实体类的名称一致

没有void等返回值

构造方法只能通过new操作符来调用,调用构造方法创建对象

class Square {int side = 1;
public Square() {}
public Square(int newSide) {side = newSide;}
public int getPerimeter() {return side * 4;}
public int getArea() { return side * side;}
}

静态(static)和实例

Java 的类成员(成员变量、方法等)可以是静态的或实例的。使用关键字 static 修饰的类成员是静态的类成员,不使用关键字 static 修饰的类成员则是实例的类成员。

静态和实例的区别

外部调用

从外部调用静态的类成员时,可以通过类名调用,也可以通过对象名调用。从外部调用实例的类成员,则只能通过对象名调用。

例如对于字符串类型 String,方法 format 是静态的,可以通过 String.format 调用,而方法 length 是实例的,只能通过 str.length 调用,其中 str 是 String 类型的实例。

建议通过类名调用静态的类成员,因为通过类名调用静态的类成员是不需要创建对象的,而且可以提高代码的可读性。

内部访问

静态方法只能访问静态的类成员,不能访问实例的类成员。实例方法既可以访问实例的类成员,也可以访问静态的类成员。

为什么静态方法不能访问实例的类成员呢?因为实例的类成员是依赖于具体对象(实例)的,而静态方法不依赖于任何实例,因此不存在静态方法直接或间接地访问实例或实例的类成员的情况。

判断使用静态或实例

如何判断一个类成员应该被定义成静态的还是实例的呢?取决于类成员是否依赖于具体实例。如果一个类成员依赖于具体实例,则该类成员应该被定义成实例的类成员,否则就应该被定义成静态的类成员。

例如对于字符串类 String,考虑方法format 和方法length

方法 format 的作用是创建格式化的字符串,该方法不依赖于任何 String 的实例,因此是静态方法(类成员)。

方法 length 的作用是获得字符串的长度,由于字符串的长度依赖于具体字符串,因此该方法依赖于 String 的实例,是实例方法(类成员)。

对于数学类 Math,所有的类成员都不依赖于具体的实例,因此都被定义成静态的类成员。

注意

static什么时候修饰一个函数

如果一个函数没有直接访问到非静态的成员时,那么就可以使用static修饰了。 一般用于工具类型的方法

静态函数不能访问非静态的成员?

静态函数只要存在有对象,那么也可以访问非静态的数据。只是不能直接访问而已

  1. 非静态的成员变量只能使用对象进行访问,不能使用类名进行访问。

  2. 千万不要为了方便访问数据而使用static修饰成员变量,只有成员变量的数据是真正需要被共享的才使用static修饰 。

static修饰成员变量的应用场景:如果一个数据需要被所有对象共享使用的时候,这时候即可使用static修饰。

代码

public class demo {public int a;public int b;public static String s = "贾永刚";public demo(int a, int b) {this.a = a;this.b = b;}public static void staticTest() {//  System.out.println(a);  static方法只能直接访问静态成员System.out.println("调用静态方法***********************");demo d=new demo(5,8);System.out.println(d.a);//不能直接访问非静态成员,想访问得先创建对象间接访问System.out.println(s);}public void test() {//实例方法可以访问静态和非静态成员System.out.println("当前方法为实例(非静态)方法");System.out.println("调用静态方法");staticTest();System.out.println("*********************");System.out.println(s);System.out.println(a);System.out.println(b);}public static void main(String[] args) {demo d = new demo(14, 2);d.test();}
}
结果:
当前方法为实例(非静态)方法
调用静态方法
调用静态方法***********************
5
贾永刚
*********************
贾永刚
14
2

final关键字

关键字 final 可以用于声明常量,表示常量不会改变。

final修饰引用变量时,只是限定了引用变量的引用不可改变,即不能将demo再次引用另一个demo对象,但是引用的对象的值是可以改变的,

public class Person {public int age;public String name;public final int id=0;public final demo demo1 = new demo(1, 2);//final修饰引用变量时,只是限定了引用变量的引用不可改变,即不能将demo再次引用另一个demo对象,但是引用的对象的值是可以改变的,public void test() {demo1.a = 2;//值更改demo1.b = 3;System.out.println(demo1.a);System.out.println(demo1.b);}
}

关键字 final 也可以用于修饰类和方法。使用 final 修饰的类是终极类,不能被继承。

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

例如,String、StringBuffer 和 StringBuilder 类都使用了关键字 final 修饰,因此这些类不能被继承。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-41TzxGSp-1659423304543)(C:\Users\fyz\AppData\Roaming\Typora\typora-user-images\image-20220326163804491.png)]

访问修饰符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PplGTniA-1659423304547)(C:\Users\fyz\AppData\Roaming\Typora\typora-user-images\image-20220326164501926.png)]

继承

在面向对象程序设计中,可以从已有的类(父类)派生出新类(子类),称为继承。

父类和子类

如果已有的类 C1 派生出一个新类 C2,则称 C1 为 C2 的父类,C2 为 C1 的子类。子类从父类中继承可访问的类成员,也可以添加新的类成员。子类通常包含比父类更多的类成员。

继承用来为 is-a 关系建模,子类和父类之间必须存在 is-a 关系。

如果一个类在定义时没有指定继承,它的父类默认是 Object。

关键字 super

【1】super:指的是: 父类的

【2】super可以修饰属性,可以修饰方法;

在特殊情况下,当子类和父类的属性重名时,你要想使用父类的属性,必须加上修饰符super.,只能通过super.属性来调用

在特殊情况下,当子类和父类的方法重名时,你要想使用父类的方法,必须加上修饰符super.,只能通过super.方法来调用

在这种情况下,super.就不可以省略不写。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VqIhnsjo-1659423304548)(C:\Users\fyz\AppData\Roaming\Typora\typora-user-images\image-20220421214534135.png)]

关键字 super 指向当前类的的父类。关键字 super 可以用于两种途径,一是调用父类的构造方法,二是调用父类的方法。

调用父类的构造方法,使用 super() 或 super(参数),该语句必须是子类构造方法的第一个语句,且这是调用父类构造方法的唯一方式。

调用父类的方法,使用 super.方法名(参数)。

构造方法链

如果构造方法没有显式地调用同一个类中其他的构造方法或父类的构造方法,将隐性地调用父类的无参数构造方法,即编译器会把 super() 作为构造方法的第一个语句。

构造一个类的实例时,将会沿着继承链调用所有父类的构造方法,父类的构造方法在子类的构造方法之前调用,称为构造方法链。

下面用一个例子说明构造方法链。考虑如下代码。

构造方法链

public class Class3 extends Class2 {public static void main(String[] args) {new Class3();}public Class3() {System.out.println("D");}}class Class2 extends Class1 {public Class2() {this("B");System.out.println("C");}public Class2(String s) {System.out.println(s);}}class Class1 {public Class1() {System.out.println("A");}
}
/*由于 Class2 是 Class1 的子类,Class3 是 Class2 的子类,因此在 Class3 的构造方法中的所有语句运行之前,先调用 Class2 的无参数构造方法。Class2 的无参数构造方法调用了有参数构造方法,在 Class2 的有参数构造方法中的所有语句运行之前,先调用 Class1 的无参数构造方法。因此,运行上述代码得到的输出结果是:A
B
C
D*/

方法的重写

子类从父类中继承方法。如果子类修改了父类中定义的方法,则称为方法重写。方法重写要求子类的方法和父类的方法的签名相同。

如果方法的返回值类型是基本数据类型或者 void,则要求子类的方法的返回值类型和父类的方法的返回值类型相同。如果方法的返回值类型是引用类型,则要求返回值类型相同或者子类的方法的返回值类型是父类的方法的返回值类型的子类。

实例方法只有当可访问时才能被重写。由于私有方法不能在定义该方法的类外访问,因此私有方法不能被重写。

静态方法可以被继承,但是不能被重写。

重写和重载的区别

重载指在同一个类中定义多个方法,这些方法有相同的名称,但是方法参数不同。

【1】什么是方法的重载:

方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。

注意本质:重载的方法,实际是完全不同的方法,只是名称相同而已!

【2】构成方法重载的条件:

❀不同的含义:形参类型、形参个数、形参顺序不同

❀ 只有返回值不同不构成方法的重载

如:int a(String str){}与 void a(String str){}不构成方法重载

❀ 只有形参的名称不同,不构成方法的重载

如:int a(String str){}与int a(String s){}不构成方法重载

总结:

1.方法的重载:在同一个类中,方法名相同,形参列表不同的多个方法,构成了方法的重载。

2.方法的重载只跟:方法名和形参列表有关,与修饰符,返回值类型无关。

3.注意:形参列表不同指的是什么?

(1)个数不同

add() add(int num1) add(int num1,int num2)

(2)顺序不同

add(int num1,double num2) add(double num1,int num2)

(3)类型不同

add(int num1) add(double num1)

4.请问下面的方法是否构成了方法的重载?

(1)add(int a) 和 add(int b) —>不构成,相当于方法的重复定义

(2)public static int add(int a) 和 public static void add(int b) —>不构成 返回值不同

重写指在子类中定义一个方法,该方法与父类中的方法的签名相同,返回值类型相同或者子类的方法的返回值类型是父类的方法的返回值类型的子类。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4veKlfpo-1659423304549)(C:\Users\fyz\AppData\Roaming\Typora\typora-user-images\image-20220326164901501.png)]

多态


什么是多态:

多态就是多种状态:同一个行为,不同的子类表现出来不同的形态。

多态指的就是同一个方法调用,然后由于对象不同会产生不同的行为。

方法调用:编译看左边,运行看右边

变量调用:都看左边

实现多态的三个条件

  • 继承的存在。继承是多态的基础,没有继承就没有多态
  • 子类重写父类的方法,JVM 会调用子类重写后的方法
  • 父类引用变量指向子类对象

向上转型:将一个父类的引用指向一个子类对象,自动进行类型转换。

  • 通过父类引用变量调用的方法是子类覆盖或继承父类的方法,而不是父类的方法。
  • 通过父类引用变量无法调用子类特有的方法。

向下转型:将一个指向子类对象的引用赋给一个子类的引用,必须进行强制类型转换。

  • 向下转型必须转换为父类引用指向的真实子类类型,不是任意的强制转换,否则会出现 ClassCastException
  • 向下转型时可以结合使用 instanceof 运算符进行判断

向上转型的好处

  • 减少重复代码
  • 提高代码扩展性

向上转型需要注意的问题

向上转型时,子类单独定义的方法会丢失。

向下转型

子类引用指向父类对象(父类型,实例是子类的实例化),通常需要进行强制类型转换,但是这里有个需要注意的问题。

向下转型时,编译期间不报错,运行时会出错(有继承关系,编译阶段可以强制转换)

向下转型需要注意的问题

  • 向下转型的前提是父类引用指向的是子类对象,也就是说,向下转型之前,它得先进行过向上转型。
  • 向下转型只能转型为本类对象(苹果是不能变成香蕉的)。
public class Main {public static void main(String[] args) {//      编译期           运行期Person pt = new teachaer();//向上转型studyP(pt);}public static void studyP(Person pt){//为了调用子类特有的行为pt.study();//共同的行为if(pt instanceof Student){Student student=(Student) pt;//编译期间不报错,运行时会出错(有继承关系,编译阶段可以强制)student.test();}else if(pt instanceof teachaer){teachaer t=(teachaer) pt;t.test();//特有的行为}}}

经典案例:

这里我们先看一句话:当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,但重点是这个被调用的方法必须是在父类中定义过的,也就是说被子类覆盖的方法。这是大前提这句话对多态进行了一个概括,其实在继承中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

class A {public String show(D obj) {       return ("A and D");     }public String show(A obj) {       return ("A and A");     }
}class B extends A{public String show(B obj){     return ("B and B");    }public String show(A obj){     return ("B and A");    }
}class C extends B{}
class D extends B{}
public class Demo {public static void main(String[] args) {A a1 = new A();A a2 = new B();B b = new B();C c = new C();D d = new D();System.out.println("1--" + a1.show(b));//A and ASystem.out.println("2--" + a1.show(c));//A and ASystem.out.println("3--" + a1.show(d));//A and DSystem.out.println("4--" + a2.show(b));//B and A 想走show(B)走不了啊,A里没有show(B),只能走show(A),show(A)在B里被重写了,走B中的show(A),不走B中的show(B),是因为这个方法B在父类中没有被定义过,a2用不了,所以最后结果时 B and A  执行的是  this.show((super)B)即this.show(A),但是由于a2是一个类B的引用对象//    的这个方法被子类B重写覆盖了,所以执行B中的show(A)this.show(object):当前类中的和形式参数类型相同的方法
super.show(object):父类中的和形式参数类型相同的方法
this.show((super)o):当前类中的和形式参数类型的父类相同的方法
super.show((super)o)父类中的和形式参数类型的父类相同的方法a2是A类型的引用变量,this就代表了A,但是a2所引用的是B对象(new B()),那么按照上面那句话的意思,a2.show(b)就应该要调用B类中的show(B obj),产生的结果就是”B and B“,但是运行结果明显不是,别忘了上面的话后面还有一句,必须是父类中定义过的方法才行,然而B的父类A中并没有show(B obj),难道上面的话是错误的?其实不是,因为它仍然要按照继承链中调用方法的优先级来确定,所以它才会在A类中找到show(A obj),由于B中重写了该方法,所以才会调用B类中的方法,所以得到的结果是B and A。*/System.out.println("5--" + a2.show(c));//B and A/*和6差不多,走this.show((super)c)首先A a2 = new B();进行向上转型,那么,a2能调用的方法还是A类中的show(D obj)、show(A obj)以及B类中的show(A obj),按照继承链中调用方法的优先级,a2是A类型的引用变量,所以继承链方法调用优先级中this.show(O)的this就代表了A,显然A类中的方法不满足这个要求,跳过,所以接下来是super.show(O),A类没有父类(除了Object类),再次跳过,然后是this.show((super)O),C继承于B,B继承于A,所以show(A obj)满足要求,由于a2变量引用的对象类型是B类型,而B类型又重写了该方法,所以最终调用的是B类中的show(A obj),所以最后输出为B and A。*/System.out.println("6--" + a2.show(d));//A and D/*首先没有,B中没有show(D),去A中看有,根据优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。走this.show(D),且A中的show(D)没有被子类B覆盖,执行this.show(D)a2是B类的引用对象,类型为A,所以this指向A类,然后在A类里面找this.show(D)方法,找到了,但是由于a2是一个类B的引用对象,所以在B类里面查找有没有覆盖show(D)方法,没有,所以执行的是A类里面的show(D)方法,即输出A and D*/System.out.println("7--" + b.show(b));//B and BSystem.out.println("8--" + b.show(c));//B and BSystem.out.println("9--" + b.show(d));//A and D}
}

编译时多态

方法重载 都是编译时多态。根据实际参数的数据类型、个数和次序,Java 在编译时能够确定执行重载方法中的哪一个。

方法覆盖 表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态。

运行时多态

通过父类对象引用变量引用子类对象来实现。当父类对象引用子类实例时。通过接口类型变量引用实现接口的类的对象来实现 。运行时多态主要是通过继承和接口实现的。

运行期多态主要是指在程序运行的时候,动态绑定所调用的函数,动态地找到了调用函数的入口地址,从而确定到底调用哪个函数

多态中的成员访问特点

A. 成员变量:编译看左边,运行看左边。
B. 构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
C. 成员方法:编译看左边,运行看右边。由于成员方法存在方法重写,所以它运行看右边。

D. 静态方法:编译看左边,运行看左边。静态和类相关,算不上重写,所以,访问还是左边的。

多态是同一个行为具有多个不同表现形式或形态的能力。

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

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

  • 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
  • 如果当前在 Word 下弹出的就是 Word 帮助;
  • 在 Windows 下弹出的就是 Windows 帮助和支持。

同一个事件发生在不同的对象上会产生不同的结果。

多态的优点

  • \1. 消除类型之间的耦合关系
  • \2. 可替换性
  • \3. 可扩充性
  • \4. 接口性
  • \5. 灵活性
  • \6. 简化性

多态存在的三个必要条件

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

抽象类和接口

抽象类指抽象而没有具体实例的类。接口是一种与类相似的结构,在很多方面与抽象类相近。

抽象类

抽象类使用关键字 abstract 修饰。抽象类和常规类一样具有数据域、方法和构造方法,但是不能用 new 操作符创建实例。

抽象类可以包含抽象方法。抽象方法使用关键字 abstract 修饰,只有方法名而没有实现,其实现由子类提供。抽象方法都是非静态的。包含抽象方法的类必须声明为抽象类。

非抽象类不能包含抽象方法。如果一个抽象父类的子类不能实现所有的抽象方法,则该子类也必须声明为抽象类。

包含抽象方法的类必须声明为抽象类,但是抽象类可以不包含抽象方法。

抽象类作用:

在抽象类中定义抽象方法,目的是为了为子类提供一个通用的模板,子类可以在模板的基础上进行开发,先重写父类的抽象方法,然后可以扩展子类自己的内容。抽象类设计避免了子类设计的随意性,通过抽象类,子类的设计变得更加严格,进行某些程度上的限制。

使子类更加的通用。

接口

接口使用关键字 interface 定义。接口只包含可见性为 public 的常量和抽象方法,不包含变量和具体方法。

和抽象类一样,接口不能用 new 操作符创建实例。

新版本的 JDK 关于接口的规则有以下变化。

从 Java 8 开始,接口方法可以由默认实现。

从 Java 9 开始,接口内允许定义私有方法。

一个类只能继承一个父类,但对接口允许多重继承。一个接口可以继承多个接口,这样的接口称为子接口。

抽象类和接口的区别

抽象类的变量没有限制,接口只包含常量,即接口的所有变量必须是 public static final。

抽象类包含构造方法,子类通过构造方法链调用构造方法,接口不包含构造方法。

抽象类的方法没有限制,接口的方法必须是 public abstract 的实例方法(注:新版本的 JDK 关于接口的规则有变化,见上文)。

一个类只能继承一个父类,但是可以实现多个接口。一个接口可以继承多个接口。

内部类

实例内部类

1.可以直接访问外部类的成员

2.在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。

3.在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。

4.外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。

5.在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。

public class Person {public static void test() {在外部类的静态方法中创建内部类对象Person.inner inner1=new Person.inner();Person.inner2 inner2=new Person().new inner2();}static class inner {静态内部类}class inner2 {实例内部类}}class test {public static void main(String[] args) {Person.inner i = new Person.inner();静态内部类创建对象不需要创建外部类的实例Person.inner2 inner2=new Person().new inner2();实力内部类创建对象,需要创建外部类的实例}
}

静态内部类

1)静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。

2)静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。

3)在创建静态内部类的实例时,不需要创建外部类的实例。

public class Outer {static class Inner {}
}
class OtherClass {Outer.Inner oi = new Outer.Inner();
}//第三条public class Outer {static class Inner {int a = 0;    // 实例变量astatic int b = 0;    // 静态变量 b}
}
class OtherClass {Outer.Inner oi = new Outer.Inner();int a2 = oi.a;    // 访问实例成员int b2 = Outer.Inner.b;    // 访问静态成员
}//第二条public class Outer {int a = 0;    // 实例变量static int b = 0;    // 静态变量static class Inner {Outer o = new Outer;int a2 = o.a;    // 访问实例变量int b2 = b;    // 访问静态变量}
}第一条

局部内部类

匿名内部类

Object 类的部分方法

toString

方法定义:

public String toString()
该方法返回一个代表该对象的字符串。该方法的默认实现返回的字符串在绝大多数情况下是没有信息量的,因此通常都需要在子类中重写该方法。

equals

方法定义:

public boolean equals(Object obj)
该方法检验两个对象是否相等。该方法的默认实现使用 == 运算符检验两个对象是否相等,通常都需要在子类中重写该方法。

hashCode

方法定义:

public native int hashCode()
该方法返回对象的散列码。关键字 native 表示实现方法的编程语言不是 Java。

散列码是一个整数,用于在散列集合中存储并能快速查找对象。

根据散列约定,如果两个对象相同,它们的散列码一定相同,因此如果在子类中重写了 equals 方法,必须在该子类中重写 hashCode 方法,以保证两个相等的对象对应的散列码是相同的。

两个相等的对象一定具有相同的散列码,两个不同的对象也可能具有相同的散列码。实现 hashCode 方法时,应避免过多地出现两个不同的对象也可能具有相同的散列码的情况。

finalize

方法定义:

protected void finalize() throws Throwable
该方法用于垃圾回收。如果一个对象不再能被访问,就变成了垃圾,finalize 方法会被该对象的垃圾回收程序调用。该方法的默认实现不做任何事,如果必要,子类应该重写该方法。

该方法可能抛出 Throwable 异常。

clone

方法定义:

protected native Object clone() throws CloneNotSupportedException
该方法用于复制一个对象,创建一个有单独内存空间的新对象。

不是所有的对象都可以复制,只有当一个类实现了 java.lang.Cloneable 接口时,这个类的对象才能被复制。

该方法可能抛出 CloneNotSupportedException 异常。

getClass

方法定义:

public final native Class<?> getClass()
该方法返回对象的元对象。元对象是一个包含类信息的对象,包括类名、构造方法和方法等。

一个类只有一个元对象。每个对象都有一个元对象,同一个类的多个对象对应的元对象相同。

反射机制

Java 反射机制的核心是在程序运行时动态加载类以及获取类的信息,从而使用类和对象的数据域和方法。

Class 类

Class 类的作用是在程序运行时保存每个对象所属的类的信息,在程序运行时分析类。一个 Class 类型的对象表示一个特定类的属性。

有三种方法可以得到 Class 类型的实例。

1.第一种方法是对一个对象调用 getClass 方法,获得该对象所属的类的 Class 对象。

2.第二种方法是调用静态方法 Class.forName,将类名作为参数,获得类名对应的 Class 对象。

3.第三种方法是对任意的 Java 类型 T(包括基本数据类型、引用类型、数组、关键字 void),调用 T.class 获得类型 T 对应的 Class 对象,此时获得的 Class 对象表示一个类型,但是这个类型不一定是一种类。

三种方法中,通过静态方法 Class.forName 获得 Class 对象是最常用的。

class m {public static void main(String[] args) throws ClassNotFoundException {Class c= Class.forName("com.Person");System.out.println(c);Class c1= Person.class;System.out.println(c1);Person person=new Person();Class c2=person.getClass();System.out.println(c2);}
}

Class 类的常用方法

Class 类中最常用的方法是 getName,该方法返回类的名字。

Class 类中的 getFields、getMethods 和 getConstructors 方法分别返回类中所有的公有(即使用可见修饰符 public 修饰)的数据域、方法和构造方法。

Class 类中的 getDeclaredFields、getDeclaredMethods 和 getDeclaredConstructors 方法分别返回类中所有的数据域、方法和构造方法(包括所有可见修饰符)。

Class 类中的 getField、getMethod 和 getConstructor 方法分别返回类中单个的公有(即使用可见修饰符 public 修饰)的数据域、方法和构造方法。

Class 类中的 getDeclaredField、getDeclaredMethod 和 getDeclaredConstructor 方法分别返回类中单个的数据域、方法和构造方法(包括所有可见修饰符)。

反射构造器可以做什么(反射获取成员,获取成员方法与之类似)

目的依然是为了创建对象 public newInstance(Object…initargs)

,如果是非public的构造器,需要打开权限(暴力反射),然后在创建对象

setAccessible(true)

反射会破坏封装,私有构造器也可以执行

class m {public static void main(String[] args) throws Exception {Class c1= Person.class;System.out.println(c1);
//        定位无参Constructor constructor=c1.getDeclaredConstructor();//这个构造方法共有无参System.out.println(constructor.getName()+"======"+ constructor.getParameterTypes());Person person =(Person) constructor.newInstance();System.out.println(person);System.out.println("*********************************");//定位某个有参构造器Constructor cos=c1.getDeclaredConstructor(int.class,String.class);//这个构造方法是私有的//如果遇到了私有构造器,可以暴力反射cos.setAccessible(true);System.out.println(cos.getName()+"======"+cos.getParameterTypes());Person p =(Person) cos.newInstance(20,"卧槽");//newInstance根据指定的构造器创建对象System.out.println(p);}
}
反射作用

绕过编译阶段向集合添加数据

public class Re {public static void main(String[] args) throws Exception {List<Integer> list1=new ArrayList<>();list1.add(1);list1.add(2);Class c=list1.getClass();Method add=c.getDeclaredMethod("add",Object.class);add.invoke(list1,"wica");//在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法System.out.println(list1);/* java.lang.reflect.Method.invoke() 方法来反射调用一个方法,当然一般只用于正常情况下无法直接访问的方法(比如:private 的方法,或者无法获得该类的对象)*/}
}
/*输出结果
[1, 2, wica]
*/

反射为何可以给约定了泛型的集合存入其它类型的元素?

编译成Class文件进入运行阶段时,泛型会被自动擦除

***************“);
//定位某个有参构造器
Constructor cos=c1.getDeclaredConstructor(int.class,String.class);//这个构造方法是私有的
//如果遇到了私有构造器,可以暴力反射
cos.setAccessible(true);
System.out.println(cos.getName()+”======"+cos.getParameterTypes());
Person p =(Person) cos.newInstance(20,“卧槽”);
//newInstance根据指定的构造器创建对象
System.out.println§;
}
}

##### 反射作用绕过编译阶段向集合添加数据```java
public class Re {public static void main(String[] args) throws Exception {List<Integer> list1=new ArrayList<>();list1.add(1);list1.add(2);Class c=list1.getClass();Method add=c.getDeclaredMethod("add",Object.class);add.invoke(list1,"wica");//在框架中经常会会用到method.invoke()方法,用来执行某个的对象的目标方法System.out.println(list1);/* java.lang.reflect.Method.invoke() 方法来反射调用一个方法,当然一般只用于正常情况下无法直接访问的方法(比如:private 的方法,或者无法获得该类的对象)*/}
}
/*输出结果
[1, 2, wica]
*/

反射为何可以给约定了泛型的集合存入其它类型的元素?

编译成Class文件进入运行阶段时,泛型会被自动擦除

反射是通用框架的底层原理

关于javase的面向对象部分的知识点的梳理,欢迎各位指正和补充相关推荐

  1. 关于python面向对象编程中、下列说法中_关于Python面向对象编程的知识点总结

    前言 如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程. 接下来我们 ...

  2. 【JavaSE】面向对象之多态、向上转型与向下转型

    本专栏为 JavaSE 的学习笔记及相关项目,专栏长期免费更新 ❤️ ❤️ ❤️ ❤️ 个人主页:Nezuko627 欢迎来访~~~ ⭐️往期回顾: [JavaSE]继承中内存发生了什么变化?这篇文章 ...

  3. JAVASE学习 面向对象

    JAVASE学习 面向对象 1.面向对象(构造方法Constructor概述和格式) A:构造方法概述和作用 给对象的数据(属性)进行初始化 B:构造方法格式特点 a:方法名与类名相同(大小也要与类名 ...

  4. java重要基础知识点_必看 | 新人必看的Java基础知识点大梳理

    原标题:必看 | 新人必看的Java基础知识点大梳理 各位正在认真苦学Java的准大神,在这烈日炎炎的夏季里,老九君准备给大家带来一个超级大的"冰镇西瓜,"给大家清凉一下,压压惊. ...

  5. 备考通信复试过程中的一些知识点总结梳理——信源编码

    信息编码可以简要分为信源编码和信道编码,我们先来介绍信源编码.信源编码的作用就是将输出信号转变为适合于数字通信系统处理和传输的数字信号,主要目的是提高传输的有效性,降低原始信号的冗余度,通常对数据压缩 ...

  6. PAT乙级题目对应知识点分类梳理例程(更新至1102)

    PAT乙级题目对应知识点分类梳理 PAT乙级的90道题的知识点与对应的题号整理如下,便于做专项练习和巩固! 题型 备注 1.字符串函数 考察字符串相关知识,如逆转.字母与数字的判断与转化.字符串拼接. ...

  7. Java虚拟机垃圾回收相关知识点全梳理(下)

    2019独角兽企业重金招聘Python工程师标准>>> 一.前言 上一篇文章<Java虚拟机垃圾回收相关知识点全梳理(上)>我整理分享了JVM运行时数据区域的划分,垃圾判 ...

  8. JAVA 面向对象和集合知识点总结

    转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46481759  在Android编程或者面试中经常会遇到JAVA 面向对象和集合的 ...

  9. 【JavaSe】面向对象篇(五) 三大特征之二继承

    JavaSe·面向对象篇(五) 三大特征之二继承 1. 面向对象三大特质之继承 1.1 由来 多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那 ...

最新文章

  1. 报告老板,微服务高可用神器已祭出,您花巨资营销的高流量来了没?
  2. deepin linux桌面设置,Deepin系统的桌面样式:高效模式和时尚模式
  3. gc日志怎么看_你应该怎么监控Kafka?
  4. java naive方法_朴素贝叶斯方法(Naive Bayes Method)
  5. java读取yaml数据_Java类读取Yaml内罐
  6. Spring AOP(四)之After增强处理
  7. smarty中的在模板页中应用js css img等文件时,地址是相对与模板页对应的php文件
  8. Atitit 提升科技影响力----软件方面的.docx 目录 1. 大原则 2 1.1. 科技强人必须是创新型[ 2 1.2. 要有一定的体量和规模 2 1.3. 产业链齐全 底层基础 --高层应
  9. 把ipa包上传到AppStore
  10. 基于Spring Boot的ERP仓储管理信息系统设计与实现毕业设计源码150958
  11. ngix 全局配置文件和子配置文件 配置项中文注释
  12. android win8 磁贴效果第三方库,Win8巧用动态磁贴让浏览更轻松
  13. 梦工厂动画CEO:不迷信大数据,只迷信耐心与好故事
  14. 变量undefined详解
  15. FLIP:Scaling Language-Image Pre-training via Masking
  16. iphone连电脑服务器未响应,今天要闻iphone8无限转圈黑屏强制关机没反应(苹果电脑开不了机黑屏)...
  17. 一文了解复旦大学NLP实验室的14篇EMNLP 2022长文内容
  18. 艾司博讯:拼多多网店账号出现异常该怎么解决?
  19. 研华工控机610L断电开机自启动
  20. 《UnityAPI.GUI界面》(Yanlz+Unity+SteamVR+云技术+5G+AI+VR云游戏+GUI+DrawTexture+FocusControl+Toggle+立钻哥哥++OK++)

热门文章

  1. 9-Nagel-Schreckenberg交通流模型-公路堵车概率模型
  2. 电信怎么关闭信息接受服务器,怎么关闭短信接收功能
  3. 开环控制系统与闭环控制系统
  4. OpenCV-细化算法(thinning algorithm)描绘出轮廓的中心线
  5. 【思维导图】canny滤波 原理步骤细致剖析
  6. java图片的在线预览_【Java】web实现图片在线预览
  7. 新爹手记-分娩篇-出生前一天(原汁原味流水版)
  8. 反射、装箱拆箱、ArrayList与Array的区别 - 天生舞男 - 博客园
  9. OneNET麒麟座应用开发之八:采集大气压力等环境参数
  10. Markdown 中的flow语法 flowchart.js 的基础教程