目录
一、认识多态
1、概念
继承、接口都是多态的具体体现方式,多态主要体现在类别、做事的方式上。多态是面向对象的三大特征之一,多态分为编译时多态和运行时多态两大类。
2、编译时多态
方法重载在编译时就已经如何调用,因此方法重载属于编译时多态。
例子
package calculate;
public class Calclate {
public int calculate(int a,int b){
return a+b;
}
public double calculate(double a,double b){
return a+b;
}
}
package calculate;
public class Calculator {
public static void main(String[] args) {
Calclate p1=new Calclate();
int a=p1.calculate(1,2);
System.out.println(a);
Calclate p2=new Calclate();
double b=p2.calculate(1.3,2.6);
System.out.println(b);
}
}
3、运行时多态
Java虚拟机(JVM)为每个变量中引用的对象调用适当的方法。它不会调用由变量类型定义的方法。这种行为称为虚拟方法调用, 它说明了Java语言中重要的多态性特征的一个方面。
例子
package calculate;
public class Father {
public void show() {
System.out.println("这是父类的show");
}
}
package calculate;
public class Child extends Father{
@Override
public void show() {
System.out.println("这是子类的show");
}
}
package calculate;
public class fatherTest {
public static void main(String[] args) {
//变量f的类型是Father
Father f = new Child();
//f调用show()时,不会调用Father定义的方法
f.show();
}
}
二、instanceof 运算符
认识使用
instanceof本身已是表示的是什么什么的一个实例。 主要应用在类型的强制转换上面。在使用强制类型转换时,如果使用不正确,在运行时会报错。而instanceof运算符对转换的目标类型进行检测,如果是,则进行强制转换。这样可以保证程序的正常运行。
语法
对象名 instanceof 类名;
//表示检测对象是否是指定类型的一个示例,返回值类型是boolean类型。
例子
package com.first.text.aniaml;
public abstract class Animal {
public void eat(){ }
}
package com.first.text.aniaml;
public class Monkey extends Animal{
@Override
public void eat() {
System.out.println("猴子吃水果");
}
//子类特有方法
public void climbing(){
System.out.println("猴子爬树");
}
}
package com.first.text.aniaml;
public class Panda extends Animal{
@Override
public void eat() {
System.out.println("熊猫吃竹子");
}
//子类特有方法
public void sleep(){
System.out.println("熊猫睡觉");
}
}
package com.first.text.aniaml;
public class Tiger extends Animal{
@Override
public void eat() {
System.out.println("老虎吃肉");
}
//子类特有方法
public void strolling(){
System.out.println("老虎在散步");
}
}
package com.first.text.aniaml;
public class FeedAnimal {
public void ZoonKeeper(Animal animal){
animal.eat();
//如果animal对象是一个Panda类的实例
if(animal instanceof Panda){
((Panda) animal).sleep();
}
//如果animal对象是一个Tiger类的实例
if (animal instanceof Tiger){
((Tiger) animal).strolling();
}
//如果animal对象是一个Monkey类的实例
if (animal instanceof Monkey){
((Monkey) animal).climbing();
}
}
}
package com.first.text.aniaml;
public class AnimalTest {
public static void main(String[] args) {
FeedAnimal p1=new FeedAnimal();
FeedAnimal p2=new FeedAnimal();
FeedAnimal p3=new FeedAnimal();
p1.ZoonKeeper(new Panda());
p2.ZoonKeeper(new Tiger());
p3.ZoonKeeper(new Monkey());
}
}
三、Object类的常用方法
引入:Object类中定义的方法大多数都是属于native方法,native表示的是本地方法,实现方式是在C++中的。
1、认识getClass()
public final class getClass()
// getClass()方法返回一个class对象,该对象具有可用于获取有关该类的信息的方法,例如
//其名称( getSimpleName() ),其超类( getSuperclass() ),及其实现的接口( getInterfaces() )。
例子
package com.oxi.abstractclass;
public class AnimalTest {
public static void main(String[] args) {
String s="s";
Class stringClass=s.getClass(); //返回一个class对象,该对象具有可用于获取有关该类的信
//息的方法
Class[] interfaceClasses=stringClass.getInterfaces();
for (int i=0;i<interfaceClasses.length;i++){
Class interfaceClass=interfaceClasses[i];
String interfaceName=interfaceClass.getSimpleName(); //获取类名
System.out.println(interfaceName);
String interfaceClassNane=interfaceClass.getName(); //获取类的全限定名
System.out.println(interfaceClassNane);
}
}
}
2、认识hashCode()
public int hashCode()
//hashCoode() 的返回值是对象的哈希码,即对象的内存地址(16进制)。
//根据定义,如果两个对象相等,则它们的哈希码也相等。如果重写了equals() 方法,则会更
//改两个对象的相等方式,并且Object的 hashcode() 实现将将不再有效。因此如果重写了
//equals() 方法,那么他的hashCode() 方法也要进行重写。
强调:Object类中的hashCode()方法返回的就是对象的内存地址。一旦重写hashCode()方法,那么0bject类中的hashCode()方法就是失效,此时的hashCode()方法返回的值不再是内存地址。根据定义,如果两个对象相等,则它们的哈希码也必须相等,反之则不然。
例子
package com.oxi.abstractclass.hashcode;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//hashCode()方法被重写后,返回值就不是对象的内存地址了
@Override
public int hashCode() {
return name.hashCode()+age;
}
}
package com.oxi.abstractclass.hashcode;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class StuTest {
public static void main(String[] args) {
Student s1 = new Student("ash", 26);
Student s2 = new Student("ash", 26);
}
3、认识equals(Object obj)
public boolean equals (Object obj)
//equals()方法比较两个对象是否相等,如果相等则返回true。object类中提供的equals()方法
//使用身份运算符 (==) 来确定两个对象是否相等。
//对于原始数据类型,这将给出正确的结果。但是, 对于对象,则不是。object提供
//的equals()方法测试对象引用是否相等,即所比较的对象是否完全相同。
//要测试两个对象在等效性上是否相等(包含相同的信息) ,必须重写equals ()方法。
例子
package com.oxi.abstractclass.hashcode;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//如果两个对象相等,那么它们的哈希码一定相等,反之则不然。
/**如果重写了equals方法,那么一定要重写hashCode方法,因为不重写hashCode方法,
* 就会调用Object类中的hashCode方法,得到的是内存地址。不同对象的内存地址是
* 不一致的。但是equals方法重写后,比较的不是内存地址,而是对象的内部信息,这样
*就会造成多个不同的对象相等却拥有不同的哈希码。
*/
//1、比较内存地址
//2、检测是否是同一类型
//3、检测属性是否相同
@Override
public boolean equals(Object o) {
if(this==o) return true;
//比较类的定义是否一致
if(this.getClass()!=o.getClass()) return false;
//类的定义一致,那么对象o就可以被强制转换为Student
Student other=(Student)o;
return this.name.equals(other.name)&&this.age==other.age;
}
//hashCode()方法被重写后,返回值就不是对象的内存地址了
@Override
public int hashCode() {
return name.hashCode()+age;
}
}
package com.oxi.abstractclass.hashcode;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class StuTest {
public static void main(String[] args) {
Student s1 = new Student("ash", 26);
Student s2 = new Student("ash", 26);
boolean a = s2.equals(s1);
System.out.println(a);
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
补充:讨论 == 和 equals 方法的区别
基本数据类型使用==比较的就是两个数据的字面量是否相等。引用数据类型使用==比较的是内存地址,equals方法来自Object类, 本身实现使用的就是==.此时它们之间没有区别。但是0bject类中的equals方法可能被重写,此时比较就需要看重写逻辑来进行。
4、认识 toString()
public String toString()
// 我们应该始终考虑在类中重写 toString() 方法
//object的toString()方法返回该对象的string表示形式,这对于调试非常有用。对象的string表
//示形式完全取决于对象, 这就是为什么你需要在类中重写toString()。
例子
package com.oxi.abstractclass.hashcode;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String
toString() {
return name+"\t"+age;
}
}
package com.oxi.abstractclass.hashcode;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class StuTest {
public static void main(String[] args) {
Student s1 = new Student("ash", 26);
Student s2 = new Student("ash", 26);
System.out.println(s1); //toString()方法重写后该行代码输出结果才是“ ash 26 ”
}
}
5、认识 finalize()
protected void finalize throws Throwable
//object类提供了个回调方法finalize (),当该对象变为垃圾时可以在该对象上调用该方法。
//object类的finalize()实现不执行任何操作,你可以厦盖finalize ()进行清理,例如释放资源。
例子
package com.oxi.abstractclass.hashcode;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
//当一个Student对象变成垃圾可能会被调用
protected void finalize() throws Throwable {
this.name=null;
System.out.println("所有资源已经被释放,可以开始清理了");
}
}
package com.oxi.abstractclass.hashcode;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
public class StuTest {
public static void main(String[] args) {
show();
//gc=> garbage collector
System.gc(); //调用系统的垃圾回收器进行回收
System.out.println("这是最后一行代码了");
}
public static void show(){
//s的对象作用范围只是在show()方法中,一旦方法执行完毕,
//那么s对象就应该消亡,释放内存
Student s=new Student("ash",26);
System.out.println(s);
}
}