Object类
引言:Java是面向对象的,在Java中所有的引用类默认继承Object类
虽然是默认继承,但也可以写上extends object 但Java是单继承,会导致不能继承其他类
所有引用类型的默认值是null(空)
引用对象(Object)中==比较的是地址是否是同一个
Object类的方法
笔试题:Object类包含哪些成员方法?
package com.easy17;
public class EasyA {
public static void main(String[] args) {
Object obj=new EasyA();
//获取类名 class com.easy17.EasyA
System.out.println(obj.getClass());
Object obja=new EasyA();
//比较内容
obj.equals(obja);
//获取哈希值
//哈希值在Java中可能是重复的
obj.hashCode();
//转换成字符串 com.easy17.EasyA@15db9742 类名@地址
System.out.println(obj.toString());
System.out.println(obj);//自动调用toString方法
//垃圾回收机制
obj=null;//取消空间的指向
System.gc();//可能会触发
}
//重写finalize
//一个对象要被销毁时执行的代码
//一个对象最后一次执行的方法,之后空间销毁
@Override
public void finalize() {
System.out.println("-----------------");
}
}
其他函数暂时没学到,例如:wait;
包(Package)
必须首行,而且是全名
包 package 声明包
使用其他包的类需要导包
包没有子父关系import java.*;只是可以使用java本包里的类,但java.util里的还是得导包
import 加包下类全名或者包.*
如:import java.util.*;
所有类默认引入java.lang
导包时类名不能重复,重复情况下可以使用类的全名指定具体使用哪个类
com.easy.EasyA a=new com.easy.EasyA();
com.easyb.EasyA b=new com.easyb.EasyA();
封装类
引言:Java是面向对象的,所有的独立的内存都应该是对象,基本数据类型不是Object(不是对象),基本数据类型用来记录数值。Java为了实现万物皆对象的理念,给每一个基本数据类型提供了一个对应的封装类型。
整数型
byte short int long
Byte Short Integer Long
浮点型
float double
Float Double
字符型
char
Character
布尔型
boolean
Boolean
性质和相关知识点
1.基本数据类型转换成对应封装类型的过程:装箱
封装类型转换成对应基本数据类型的过程:拆箱
2.基本数据类型的封装类可以和基本数据类型直接转换
转换关系
(个人验证的,不一定对,大部分情况适用)
1.基本数据类型的封装类可以和基本数据类型直接转换
int num=12;
Integer a=num;
a.toString();//可以调用封装的方法
a++;
a+=10;
System.out.println(a+" "+num);//23 12
2.封装类型可以转换为其他基本数据类型(遵循基本类型之间的转换关系)
long b=a;
拆箱后隐式转换实现的都可以
double d=a;//d=Double.valueOf(a); 拆封后隐私转换为double
拆箱后强转实现的都会报错
//byte c=(byte)a;//报错 因为要转两次先转int后转byte不能一次实现(隐式转换没有影响)
//封装类型之间不能相互转换
//Long b=a;报错
封装类的缓存机制
基本数据类型的封装类型的缓存 防止内存占用过多
整数型:整数型缓存一个byte范围(-128~127)
Integer的缓存范围可以调整 具体方法和JVM设置有关 我不知道
字符型:字符类型缓存范围(0~127)(没有负数)
布尔型:布尔类型两个值都缓存
浮点型:没有缓存
· 验证:
Integer intA=12;
Integer intB=12;
System.out.println(intA==intB);//true
Integer intC=200;
Integer intD=200;
System.out.println(intC==intD);//false
Integer intE=new Integer(12);//不使用缓存,占用内存开辟新地址
System.out.println(intE==intB);//false
其他注意点
1.封装类型和基本数据类型比较封装类型会先拆箱
int aa=12;
System.out.println(intA==aa);
2.封装类型之间类型不一样就不能比较
System.out.println(intA==d);//报错
3.都有valueof静态方法
Integer.valueOf("100");//返回封装类型
4.都有parseInt或parseDouble等静态方法
Integer.parseInt("100");//返回基本类型
Double.parseDouble("100");
5.由于对于操作符==,如果一个是基本类型、一个是包装类型,在比较前会先把包装类型拆箱成基本类型,然后进行比较。
对于同样是包装类型的变量b、c,操作符==比较的是它们的引用,而一个是缓存中数据,一个在堆中,所以b == c为false。
static修饰符
注意点:
1.静态属性只能在类中定义,不能在方法中定义(局部变量)
2.静态方法不能被重写 本事就是为了用类名直接调用的
3.静态方法不能使用非静态属性和方法
package com.easy17;
public class EasyD {
public static void main(String[] args) {
StaticObject a=new StaticObject();
StaticObject b=new StaticObject();
a.maxAge=10;//此时b.maxAge也为10;所有对象共享
int maxAge=StaticObject.maxAge;
}
}
class StaticObject {
//static 静态的 类的
int age;//成员属性
static int maxAge;//类的属性 可以使用类名直接调用static修饰的属性和方法,也可以使用实例对象
public static void f() {
//age=10;//静态方法不能使用非静态属性和方法
new StaticObject().age=10;//非直接;
}
@Override
public String toString() {
return "StaticObject [age=" + age + "]";
}
}
final修饰符
用途:
1.可以修饰类 代表最终类(不能被继承) 故final和abstract不能一起使用
2.final可以修饰方法 代表最终方法,不能被重写
3.final可以修饰量 代表最终量,声明时就要初始化
4.成员最终量要么声明就初始化要么构造函数里初始化
例子:
final int num;
EasyF(int num){
this.num=num;
}
注意点:
不能被重新赋值(引用不能指向新的地址,但指向地址的内容可以改变)
final int[] arr={1,2,3};
arr[2]=2;
抽象类
抽象类是一种包含抽象方法的类,它本身无法被实例化。
用途: 抽象类用来被继承
和普通类区别
1.使用abstract修饰的类是抽象类(abstract和static不能同时使用)
2.抽象类没有直接实例 不能new(可以有构造方法)
3.抽象类中可以定义抽象方法
抽象方法
抽象方法是只有方法声明而没有方法实现的方法,必须在子类中实现。
抽象方法用abstract修饰,没有方法体
public abstract void methodB(int a);
注意点
1.抽象类可以有构造方法 //给子类super()的
2.抽象类可以继承实体类 (例:所有类都是Object的子类)
3.抽象类继承抽象类不需要重写,因为抽象类可以拥有抽象方法
使用:实体类继承抽象类必须实现抽象类的抽象方法(重写)
package com.easy17;
public abstract class EasyE {
//抽象类
//用途 抽象类用来被继承
//给子类super()的
EasyE() {}
public void methodA() {}
//抽象方法用abstract修饰,没有方法体
public abstract void methodB(int a);
}
//抽象类可以继承实体类 (所有类都是Object的子类)
class Son extends EasyE{
//实体类继承抽象类必须实现抽象类的抽象方法(重写)
@Override
public void methodB(int a) {
System.out.println("methodB");
}
}
abstract class EasyEe extends EasyE{
//抽象类继承抽象类不需要重写,因为抽象类可以拥有抽象方法
}
接口
接口是一种抽象数据类型,它定义了一组方法的规范,但没有具体的实现。
定义接口
interface IVehicle extends Cloneable{
//接口内部只能定义方法但没有方法体和构造方法
//抽象方法 没有具体实现的方法
//接口中定义的方法默认使用public abstract修饰
void transport();
//定义属性 只能是静态常量 常量必须声明时初始化
public static final String MAX_SPEED="200";
//不写系统也默认public static final修饰
public final String s="222";
String MIN_SPEED="100";
//不能使用其他修饰符修饰
//protected static final String MAX_SPEED="200";//报错
default void f() {}//jdk1.8后允许
//default修饰但访问权限还是public
}
命名规范:命名要加I后面和类一样
实现接口
1.java中使用implements声明一个类实现接口 class 类名 implement 接口名, 接口名
2.一个类可以实现多个接口
3.接口使用extends继承多个接口
4.抽象类可以实现接口
5.接口不能继承类
6.如果两个接口有相同的函数名和参数列表则不能同时被继承或者实现
class ObjectInter implements IVehicle{
public void transport() {
System.out.println("实现方法");
}
}
克隆
前提:
1.对象才能克隆(引用类型)
2.被克隆的对象必须实现Cloneable接口(空接口,标记作用),不实现会有异常
3.Object里有但是是protected修饰调用不了,所以需要重写
浅拷贝
只拷贝自身,不拷贝关联的属性(关联的属性直接复制指向的地址)
package com.easy17clone;
public class Easy {
public static void main(String[] args) throws CloneNotSupportedException {
//浅拷贝 只拷贝自身,不拷贝关联的属性(关联的属性直接复制指向的地址)
Teacher tea=new Teacher("唐僧");
Student stu=new Student();
stu.teacher=tea;
System.out.println(stu);//Student [tea=Teacher [name=唐僧]]
Object obj=stu.clone();
System.out.println(obj);//Student [tea=Teacher [name=唐僧]]
stu.teacher.name="李世民";
System.out.println(stu);//Student [tea=Teacher [name=李世民]]
System.out.println(obj);//Student [tea=Teacher [name=李世民]]
}
}
class Student implements Cloneable{
Teacher teacher;
@Override
public String toString() {
return "Student [tea=" + teacher + "]";
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
//面试题:深拷贝浅拷贝
class Teacher{
String name;
@Override
public String toString() {
return "Teacher [name=" + name + "]";
}
public Teacher(String name) {
super();
this.name = name;
}
}
深拷贝
克隆自身的同时克隆关联的属性
package com.easy17clone;
public class Easy {
public static void main(String[] args) throws CloneNotSupportedException {
//深拷贝 克隆自身的同时克隆关联的属性
Teacher tea=new Teacher("唐僧");
Student stu=new Student();
stu.teacher=tea;
System.out.println(stu);//Student [tea=Teacher [name=唐僧]]
Object obj=stu.clone();
System.out.println(obj);//Student [tea=Teacher [name=唐僧]]
stu.teacher.name="李世民";
System.out.println(stu);//Student [tea=Teacher [name=李世民]]
System.out.println(obj);//Student [tea=Teacher [name=唐僧]]
}
}
class Student implements Cloneable{
Teacher teacher;
@Override
public String toString() {
return "Student [tea=" + teacher + "]";
}
public Object clone() throws CloneNotSupportedException {
//克隆自身的同时克隆关联的属性
Object obj=super.clone();//将当前对象克隆一份
Object objTeacher=this.teacher.clone();//将当前对象的Teacher属性克隆一份
((Student)obj).teacher=(Teacher)objTeacher;
return obj;
}
}
class Teacher implements Cloneable{
String name;
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Teacher [name=" + name + "]";
}
public Teacher(String name) {
super();
this.name = name;
}
}
面试题总结
Object类包含哪些成员方法?
在Java语言中,所有类都是继承自Object类的,因此Object类中包含了一些常用的成员方法。以下是Object类中常用的成员方法:
1. equals(Object obj):用于判断两个对象是否相等。
2. hashCode():返回对象的哈希码值。
3. toString():返回对象的字符串表示。
4. getClass():返回对象的运行时类。
5. notify():唤醒在该对象上等待的线程。
6. notifyAll():唤醒在该对象上等待的所有线程。
7. wait():使当前线程等待,直到其他线程调用notify()或notifyAll()方法唤醒它。
8. finalize():当对象被垃圾回收器回收时调用。
除此之外,Object类还包含一些其他方法,如clone()、finalize()等。需要注意的是,这些方法是Object类提供的通用方法,可以被所有的子类继承和使用。
深浅拷贝的区别
深拷贝和浅拷贝是在Java中常见的两种对象复制的方式,它们的区别在于复制的深度和复制的方式。
浅拷贝(Shallow Copy):浅拷贝是指在对象拷贝时,只复制对象本身和内部对象的引用,而并没有复制对象的内容。
深拷贝(Deep Copy):深拷贝是指在对象拷贝时,不仅复制对象本身,还会递归地复制对象内部的引用类型数据。复制的对象和原对象完全独立。
总结:
- 浅拷贝不会复制对象内部的引用类型数据,复制的对象仍然共享引用类型数据;
- 深拷贝会递归地复制对象内部的引用类型数据,复制的对象和原对象完全独立。
在实际应用中,需要根据具体情况选择使用浅拷贝还是深拷贝。如果需要复制对象的内部引用类型数据,就应该使用深拷贝;如果只需要复制对象本身以及基本数据类型,就可以使用浅拷贝。
抽象类和接口的区别
抽象类是一种类,可以包含具体的方法和抽象方法,而接口只能包含抽象方法和常量。一个类可以实现多个接口,但只能继承一个抽象类。这是Java抽象类和接口之间的主要区别。
何时选用抽象类?什么时候选用接口?
选用抽象类的情况:
1. 当一个类需要实现共有的方法和属性,并含有一些方法的实现细节,但又希望子类进行定制化实现时,可以使用抽象类。
2. 当一个类需要继承多个类或者实现多个接口时,由于Java不支持多重继承,可以通过抽象类来实现多个接口的功能。
3. 当想要提供公共行为的同时保留灵活性和扩展性时,可以使用抽象类。
选用接口的情况:
1. 当一个类不想继承某个类但需要实现某些方法时,可以使用接口。
2. 当一个类想要实现多态的功能,即一个类可以表现出不同的行为,使用接口可以方便地实现这样的功能。
3. 当希望定义一个模块的行为,但是模块可能会被不同的类实现时,可以使用接口。
总的来说,在用于定义一组相关类的共有行为,提供一定程度的默认实现以及建立类的层次结构的时候,优先考虑选择抽象类;如果希望实现一种规范或者约定,并且支持多重继承和多态的功能,可以选用接口。