java学习第八天
多态
一个类在编译的时候和运行时同一个方法可能会呈现出不同的状态。
比如:动物类都有一个会跑的方法,它的子类有一个乌龟,乌龟跑得慢。还有一个子类是狗类,狗跑得快
现在有一个动物类的对象,调用跑的方法,有可能跑得快,也可能跑得慢。
多态的形成条件
- 有继承关系,有多个子类,子类重写父类的方法
- 父类的类型定义的变量,用子类的实例给它赋值
多态的作用:
-
统一管理,无线适配或扩展。
(例如:windows操作系统有打印功能,但是不知道用户要用什么样的打印机,所以他就规定一个方法。不同的打印机(针式、喷式、激光等)只要继承重写打印方法,就可以实现自动适配所有的打印机。
-
Animal.java
public class Animal { public void run(){ System.out.println("动物在跑"); } }
-
Dog.java
public class Dog extends Animal{ @Override public void run() { System.out.println("狗跑得快"); } }
-
Turtle
public class Turtle extends Animal{ @Override public void run() { System.out.println("乌龟跑得慢"); } }
-
Test
public class Test { public static void main(String[] args) { Animal animal = new Animal(); animal.run(); Dog dog = new Dog(); dog.run(); Turtle turtle = new Turtle(); turtle.run(); System.out.println("=========狗叫====="); Animal animal1 = dog; animal1.run(); System.out.println("=========乌龟======"); Animal animal2 = turtle; animal2.run(); } }
运行结果
动物在跑 狗跑得快 动物在跑 乌龟跑得慢 =========狗叫===== 狗跑得快 =========乌龟====== 乌龟跑得慢
向上造型
父类 变量 = new 子类();
父类定义的变量,用子类的实例对象赋值。
注意:向上造型时,不能调用到子类中自己添加的方法。
System.out.println("=========狗叫=====");
Animal animal1 = dog;
animal1.run();
System.out.println("=========乌龟======");
Animal animal2 = turtle;
animal2.run();
向下造型
子类 变量 = (子类)父类的对象;
用父类的对象给子类的变量赋值,向下造型必须用强制类型转换。
向下造型分为几种情况:
- 直接new一个父类的对象,赋给子类的变量,运行时会抛异常(不允许)。
- 父类对象是通过子类的对象向上造型上去的实例,这种对象可以向下造型,但也要强制类型转换。子类的所有方法都可以访问到
- 与2一样的做法,但是换了同级的不同子类,如狗的子类对象,向下造型成乌龟,运行时也会抛出异常(不允许)。
//1. 直接用父类创建的对象赋给子类变量,会抛出异常
Dog cat = (Dog) new Animal();
//2.把通过向上造型得到的父类对象赋给子类对象,可以调用继承自父类的方法,也可以子类自己的方法
System.out.println("=====向下造型=====");
Animal animal1 = dog;
Dog dog1 = (Dog) animal1;
dog1.run();
dog1.eat();
//3.一个父类的不同子类之间转换。
Animal animal2 = new Dog();//Dog赋给animal2
Turtle turtle1 = (Turtle) animal2;//animal2赋给turtle
turtle1.run();
turtle1.eat();
static修饰符(静态的)
static也是一种修饰符,他表示静态的意思,他可以修饰属性,方法,代码块
用static修饰的属性或方法称为静态的成员,它属于类的(不属于对象),所以可以直接使用。
静态的方法用于高频访问的方法(比如工具类的方法),方便调用
静态属性用于所有对象共享的属性(他只有一次,保存在类上的)
- 静态的属性和方法
public class Parent {
public static float pi = 3.14F;
public static void area(float r){
System.out.println(pi * r *r);;
}
}
- 静态的属性和方法可以直接用类名访问。
public class ParentTest {
public static void main(String[] args) {
System.out.println(Parent.pi);
Parent.area(5);
}
}
静态属性用于所有对象共享的属性。(只有一份,保存在类上)
public class Parent {
public static float pi = 3.14F;
public static int count;//属于类,只保存一次(共享的值)
public int num;
public static void area(float r){
System.out.println(pi * r *r);;
}
public static float getPi() {
return pi;
}
public static void setPi(float pi) {
Parent.pi = pi;
}
public int getNum() {
return num;
}
public int getCount(){
return count;
}
public void setNum(int num) {
count = num;
this.num = num;
}
}
测试结果
非静态成员是对象独有,互不干扰的
静态成员变量是所有对象共有的,任何一个对象改变了他,其他对象都能看到其改变后的结果。他不属于对象,属于类。
Parent parent1 = new Parent();
Parent parent2 = new Parent();
parent1.setNum(5);//parent1对象设置为num = 5,count = 5
parent2.setNum(8);//parent2对象设置为num = 8,count = 8
System.out.println(parent1.getNum());//5
System.out.println(parent1.getCount());
System.out.println(parent2.getNum());//8
System.out.println(parent2.getCount());
System.out.println(Parent.count);//8
-
静态的成员变量访问的条件
-
静态的成员变量在非静态的方法里可以访问
-
静态方法中才能访问静态成员变量
-
静态方法不能访问非静态属性
public static void getData(){ //System.out.println(num);非静态的方法不能访问非静态的属性 System.out.println(count);//静态的方法才能访问静态的成员变量 }
-
static修饰代码块
语法:
static{
//要执行的代码
}
静态代码块在类加载时执行(在构造方法之前),与它在类中的位置无关。
静态代码块一般用于初始化、条件准备或运行其他方法之前必须要先执行的代码
static {
//在类加载的时候执行一次
//在类中的位置无关,一般会放在成员变量和方法之间
//会在构造方法之前执行
System.out.println("静态代码块");
}
jvm内存模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k8lTEziS-1659152190637)(C:\Users\hanhan\Desktop\java基础笔记\java面向对象第8天\QQ图片20220729145017.jpg)]
Object对象及它的方法
Object类是所有类的父类,我们的类没有明确写继承Object(extends Object)他都会默认继承Object。
Object类有几个方法,所有的类都会继承这几个方法,有需要的时候也可以重写这些方法。
-
toString()
如果一个对象直接用于显示,它默认会去调toString(),把返回的内容显示出来。
对象的toString()方法默认返回类的全限定名再加上对象的地址(ID),这个信息没有太大的参高价值,所以我们经常重写toString()方法,返回属性的值。
@Override public String toString() { return "Student{" + "num=" + num + ", name='" + name + '\'' + '}'; }
-
equals()和hashCode()
hash是一种算法,根据一定的内容生成一个hash code值,用于判断两个内容是否一样的。
-
equals()方法判断两个对象是否内容相等,它依耐hashCode()方法。
@Override public boolean equals(Object o) { //首先比较地址是否相等 if (this == o) return true; //要比较的对象是否是null || 判断两个对象是否是同一个类创建的,如果不是,那就不相等。 if (o == null || getClass() != o.getClass()) return false; //对要比对的内容强制转换,因为传过来的参数是Object。 Student student = (Student) o; return num == student.num && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(num, name); }
测试:
Student student = new Student(); student.setName("张三"); student.setNum(1905555000); System.out.println(student); Student student1 = new Student(); student1.setName("张三"); student1.setNum(1905555000); System.out.println(student1); //对象用 == 比较,比较的是它们的地址 System.out.println(student == student1); //用equals判断两个对新疆,equals返回true,那么两个对象就相等 System.out.println(student.equals(student1)); /* String s = student.toString(); System.out.println(s); //直接打印对象,返回值就是toString()的返回内容 //默认的toString()方法返回格式如下:com.HQYJ.ObjectDome.Student@4eec7777 System.out.println(student);*/ }
==与equals
基本类型判断是否相等==
应用(对象)类型用 == 判断,只是判断对象的地址,如果相等,说明是指向堆中的同一个对象。
逻辑上判断两个对象是否相等,需要用equals方法,往往需要重写equals。
注意:字符串的字面量赋值的时候,不会生成对象,而是存放在常量池,常量池中的字符是可以共享的。
System.out.println("=========双等和equals=====");
short s = 65;
int i = 65;
char c = 65;
System.out.println(s == i);
System.out.println(i == c);
//基本类型用 == 比较,它是比较的值,跟类型无关
String str = new String("abc");
String str2 = new String("abc");
System.out.println(str == str2);//false
System.out.println(str.equals(str2));//true
String str3 = "xyz";
String str4 = "xyz";
//字面量赋值的字符串会保存在字符串常量池里。并不会创建一个对象。
System.out.println(str3 == str4);//true
System.out.println(str.equals(str4));//true
-
getClass()
返回类的Class类型的对象。
每一个类加载到方法区的时候都会生成一个Clas类型的对象,这个对象就是负责访问类的字节码。
-
finalize()
gc(垃圾回收器),回收对象之前调用的一个方法。
-
notify 及 walt等方法
这些方法是多线程使用的。
final
final意思是最终的,它也是修饰符,他可以修饰类,成员变量,方法。
-
修饰属性
- 修饰成员变量时要赋值,static1 final修饰的成员变量就是常量
- 修饰局部变量,可以先定义在赋值
- 不管时修饰哪一种变量,只能被赋值一次,再也不能被修改
//修饰成员变量 //static加final修饰的成员变量,就是一个常量。 public static final float pi = 3.14F; public static int count;//属于类,只保存一次(共享的值) public int num; //final的成员变量必须要初始化 //final的变量不能再被赋值(值初始化之后就不能在改变) public final int flag = 0; //修饰局部变量 public int getNum() { final int i; i = 2; //i = 3;只能赋值一次,不能重复赋值 System.out.println(flag); System.out.println(i); return num; }
-
修饰方法
-
final修饰的方法不能被重写
public final void test(){ }
-
修饰类
final修饰的类不能被继承
public final class Parent { }
final、finallize、finally的区别
他们没有相同性,唯一相同的就是单词都是有final,很容易混淆,经常被作为面试题
-
final是一个修饰符(关键字),被final修饰的属性不能被修改,被final修饰的方法不能被重写,被final修饰的类不能被继承。
-
finallize是Object对象的一个方法,这个方法在垃圾回收之前会被调用。
-
finally是异常语句的一个分支,finally分支的代码一定会被执行。
try{ //可能会出异常的代码 }catch(){ //异常的处理代码 }finally{ //代码一定会被执行,一般用于资源的回收关闭 } ``