1. Object
1.1 概述
Object: 是Java中提供一个根类,类的祖宗
所有类都直接或者间接的继承了Object
如果一个类没有显示继承一个父类的话,那么该类默认继承Object
既然Object 是所有类的祖类,也就意味着Object中的方法是所有类都有的功能
Object xxx = new xxxx() 是可以发生多态的
因为多态的原因,如果一个方法需要传递数据,我们不能确定数据的类型的时候,可以写Object
1.2 equals
关于Object中的equals方法
public boolean equals(Object obj){
return (this==obj);
}
==: 两边如果是基本数据类型,则比较值的大小,但是两边如是引用类型,则比较内存地址
而Object 中 的equals方法默认比较内存地址。因此要想改变比较内容,通过成员方法public boolean equals(Object obj){}覆写
设计目的:比较两对象是否相等
但是,它没有实现该功能,因为不知道怎么实现,不知道你要比较什么属性,所以没法实现。
需要根据自己的需求进行重写,因为使用者一定知道怎么判断相等
两个对象可以是任何东西,但是我们肯定要拿两个对象的有意义属性进行比较
而不是比较内存地址,所以这个时候需要将两个对象对应的equals方法进行覆写,以满足我们的需求。但是不同类的对象,没有可比性
package com.demo.equals;
public class _01_Equals {
public static void main(String[] args) {
Student s1 = new Student(18,"张三");
Student s2 = new Student(12,"张三");
//打印s1 ,s2 地址
// System.out.println(s1);//com.demo.equals.Student@15db9742
// System.out.println(s2);//com.demo.equals.Student@6d06d69c
//先用==进行比较,由于==是比较地址会返回false
System.out.println(s1==s2);//false
//用equals进行比较,此时没有对equals进行覆写
//结果为false,只是因为equals 是用的Object里的方法,方法如下
// public boolean equals(Object obj) {
// return (this == obj);
// }
//this是被调用的地址,这里指的是s1的地址,而obj是s2
//返回的是 this == obj,表示s1 == s2 地址是否相同,不是为false
// System.out.println(s1.equals(s2));//false
//覆写equals 方法
System.out.println(s1.equals(s2));//true
System.out.println(s1.equals("adasds"));//false
System.out.println(s1.equals(s2));
}
}
class Student{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student() {
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
//需求:name 相等就是同一个学生
@Override
public boolean equals(Object obj) {
//1 比较地址,地址相等,值一定相等
if(this == obj) {
return true;
}
//2 判断类型是否为当前类型,否则返回fasle
//用instanceof 判断该对象是否有实例化对象而来
//
if(obj instanceof Student) {
//强制转换,比较想要比较的数据
Student s2 = (Student)obj;//类型向下转型
// System.out.println(s2);//com.demo.equals.Student@6d06d69c
if(name.equals(s2.name) ) {
//这里的name 是String类型,再String中,也有个equals覆写方法
//会判断String 里面的char字符是否一样
/**
* public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}*/
return true;
}
// //想要比较age
// if(age == s2.age) {
// return true;
// }
// //既要比较age又想比较名字
// if(name.equals(s2.name) && age == s2.age) {
// return true;
// }
}
return false;
}
}
比较字符串是否相等 应该用equals ,这是因为 == 比较内存地址,并且String覆写equals方法,比较得是值,而并不是地址
任何得引用类型比较,都必须转化为基本类型比较,除非想知道它们的内存地址是否一致
因为== != 只能比较基本数据类型,当两个对象比较的时候,会比较内存地址
而我们比较的时候应该拿某一个相同的属性的值去比较,所以这样最终还是会变成基本数据类型
面向对象就是一种基本数据类型封装的形式,比较的时候最终都要转换为基本数据类型
package com.demo.equals;
public class _02_Equals {
public static void main(String[] args) {
String s1 = new String("123");
String s2 = new String("123");
//地址不一样
System.out.println(s1 == s2);//false
//String中有equals覆写方法
System.out.println(s1.equals(s2));//true
}
}
1.3 toString
设计目的: 返回该对象的字符串表示,可以通过这个办法,把每个对象的数据展示出来。
输出一个引用类型的时候,会自动调用该对象的toString方法
Object 中的toString
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
package com.demo.toString;
public class _01_toString {
public static void main(String[] args) {
String s1 = new String("123");
//打印的结果不是地址,因为String中覆写了toString
System.out.println(s1);//123
Person p1 = new Person(18,"张三");
//没有覆写toString方法
// System.out.println(p1);//com.demo.toString.Person@15db9742
//覆写了toString方法
System.out.println(p1);//姓名: 张三, 年龄: 18
//对于打印为什么调用了toString方法
//println方法
// public void println(Object x) {
// String s = String.valueOf(x);
// synchronized (this) {
// print(s);
// newLine();
// }
// }
//点击valueOf(x)方法
// public static String valueOf(Object obj) {
// return (obj == null) ? "null" : obj.toString();
// }
//看出当传入的值为对象的话,如果对象不为空则执行obj.toString()方法
//obj.toString()
// public String toString() {
// return getClass().getName() + "@" + Integer.toHexString(hashCode());
// }
//而我们对toString覆写可以改变返回值,得到需求要的东西
}
}
class Person{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {}
public Person(int age,String name) {
super();
this.age = age;
this.name = name;
}
//覆写toString方法
@Override
public String toString() {
return "姓名: " + name + ", 年龄: " + age;
}
}
1.4 hashCode
hashCode 设计目的:是为了给每个对象生成一个唯一的标识符
同一个对象生成多次hash值,值一定是一样的
但是不同对象,生成的值也可能相同,这样又叫做哈希冲突
既然有哈希冲突的情况,所以hash就不能保证数据的唯一性:
1 先比较哈希,如果哈希不同,对象则不同
2 如果哈希值相同,再比较对象是否相同(equals)
覆写hashCode 的时候,还需要考虑什么? equals
覆写equals的时候,还需要考虑什么? hashCode
因为再java 中可以通过hashCode 和 equals来表示对象的唯一性
hash 算法: 是一种安全的加密算法,把不定长的值,改为定长的值,并且不能保证其唯一性
package com.demo.hashCode;
public class _01_HashCode {
public static void main(String[] args) {
_01_HashCode hc = new _01_HashCode();
int hash = hc.hashCode();
System.out.println(Integer.toHexString(hash));//15db9742
System.out.println(hc);//com.demo.hashCode._01_HashCode@15db9742
}
// @Override
// public int hashCode() {
// return 1;
// }
}
1.5 finalize
finalize 方法功能
垃圾被回收之前,自动调用该方法,想做什么,自己覆写 Object
1 finalize 是每个对象都有的方法
2 不需要程序员去调用,由系统自动调用
3 java 中如果每个更多引用指向这个对象,那么该对象被视为垃圾数据,等待被回收,被回收之前,自动调用finalize 方法
4 finalize方法 没有垃圾回收功能,只能用于被回收之前做的一些事而已,回收时JVM去做的,所以程序员就算手动调用这个方法,也只是一个普通的成员方法调用而已,和对象收回没有任何关系
5 一般用于做一些对象回收前的数据销毁操作
package com.demo.finalize;
public class _01_Finalize {
public static void main(String[] args) {
Animal animal = new Animal();
animal = null;
//程序员只能建议 垃圾回收器回收
// System.gc();//com.demo.finalize.Animal@554dfb98马上要被回收了
//gc()
// public static void gc() {
// Runtime.getRuntime().gc();
// }
//gc()
// public native void gc();
//native是一个计算机函数,一个Native Method就是一个Java调用非Java代码的接口。方法的实现由非Java语言实现,比如C或C++。
//如果垃圾过多,不用建议,自动回收
for(int i=0;i<99999999;i++) {
new Animal();
}
}
}
class Animal{
public void finalize() {
System.out.println(this+"马上要被回收了");
}
}
2.类关系
package com.demo.ClassRelation;
public class Test {
// 成员变量,是另一个类对象的引用,关联关系
B b = new B();
public static void main(String[] args) {
// 局部变量,是另一个类对象的引用,依赖关系
A a = new A();
}
}
//类和接口多实现,逗号隔开
class A implements C,D{}
//继承,类和类时单继承
class B extends A{}
interface C{}
interface D{}
内部类
3.1 概述
当一个事物的内部,还有一部分需要一个完整的结果进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类
在java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类
InnerClass 一般用于在定义它的类或语句块之内,在外部引用它时必须给出完整的名称
3.2 分类
static 成员内不类
非static成员内部类
局部内部类
匿名内部类
3.3 成员内部类
变量:
成员变量:成员内部类
静态变量:静态内部类
局部变量:局部内部类
形参和实参变量:匿名内部类
成员内部类:
1 可以等同看做成员变量
2 成员内部类中不能有静态声明
3 成员内部类中可以直接访问外部类所有属性
package com.demo.InnerClass;
public class _01_OuterClass {
private static String s1 = "A";
private String s2 = "B";
public static void main(String[] args) {
//Illegal modifier for parameter s1; only final is permitted
//这么写变成常量了
// private static String s1 = "A";
// 创建外部类对象
_01_OuterClass oc = new _01_OuterClass();
// 通过外部类对象去创建成员内部类对象
InnerClass ic = oc.new InnerClass();
ic.m2();
}
// private,public,protected 都可以使用
// 编译后的类名为 外部类类名$内部类类名
// _01_OuterClass$InnerClass
class InnerClass {
// 不能有静态声明
// static int x = 2;
// public static void m1(){ }
public void m2(){
// 可以直接访问外部类的所有属性
System.out.println(s1);
System.out.println(s2);
}
}
}
package com.demo.InnerClass;
public class _02_OuterClass {
private static String s1 = "A";
private String s2 = "B";
// 静态内部类
private static class InnerClass{
public static void m1(){
System.out.println(s1);
// 不能直接访问成员属性
// System.out.println(s2);
// 需要用对象调用
_02_OuterClass s = new _02_OuterClass();
System.out.println(s.s2);
}
public void m2(){
System.out.println(s1);
// 不能直接访问成员属性
// System.out.println(s2);
}
}
public static void main(String[] args) {
// 外部类.内部类.静态
_02_OuterClass.InnerClass.m1();
// 访问当前类的静态属性的时候,类名可以省略(外部类)
InnerClass.m1();
InnerClass ic = new _02_OuterClass.InnerClass();
InnerClass ic1 = new InnerClass();
ic.m2();
}
}