Object
位置:java.lang
所有的类都会直接或者间接的继承Object父类
当创建所有对象的时候,都会创建一个Object对象
使用父类引用指向子类的对象的原理,创建一个方法,方法中形式参数Object,则该方法可以传入除了基本数据类型意外的所有类型的数据当做实际参数
class Person{
public void test(Object o) {
System.out.println("test执行");
}
public void test(Object[] o) {
System.out.println("test执行");
}
}
class Dog{}
public class work {
public static void main(String[] args) {
Person p=new Person();
int[] i=new int[5];
p.test(p);
p.test(new Dog());
p.test(i);
//p.test1(new Dog());
}
}
Object下的重要方法
1)toString()
2)equals()
3)hashcode()
toString()
功能:将对象转换成字符串
可以在自己的类下重写toString方法
class Person{
public String name;
public int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
public class work {
public static void main(String[] args) {
Person p=new Person("张三",20);
// System.out.println(p.toString());toString被重写了
System.out.println(p);
}
}
equals方法
功能:Object下的equals等价于==
面试题:equals等价于==有什么区别?在object下是一样的
所有的类都可以重写equals方法,一般来说,就都将它重写成比较内容是否一致
class Person{
public String name;
public int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public boolean equals(Object others) {
//others(父类类型)转换成子类类型:向下造型
Person othersPerson=(Person)others;
if(this.name.equals(othersPerson.name)&&this.age==othersPerson.age) {
return true;
}
return false;
}
}
public class work {
public static void main(String[] args) {
//对于字符串类型来说,重写equals方法,字符序列相同则判定两个字符串相同
Person p=new Person("张三",20);
Person p1=new Person("张三",20);
System.out.println(p==p1);
System.out.println(p.equals(p1));
//String s="abc";
//String s1="abc";
//System.out.println(s==s1);
//System.out.println(s.equals(s1));
}
}
hashcode()
功能:在Object中返回对象hash码值(针对一个地址会产生一个唯一标示)
在应用的时候,很多API都将hashcode给重写了,认为两个对象如果一致,则让两个对象的hashcode返回同一个值
hashcode()返回值跟equals方法保持一致
如果两个对象equals方法比较,返回true,则让hashcode()的返回值相等,否则false,则让hashcode()的返回值不相等
【注意】System.identityHashCode(Object o)的真正的hashcode,跟Object中hashcode()方法的返回值是一个
hashcode()方法的返回值不一定是hashcode
System.identityHashCode(Object o)才是真正的hashcode
public class Day7_2_Object {
public static void main(String[] args) {
Object object=new Obejct();
object.hashCode()
System.identityHashCode(x)
}
}
抽象
【注意】面向对象的三大特征中没有抽象
【原因】抽象的本质是为了完善继承
【抽象的背景】发现代码有多余的时候,可以将类设计成:父类,子类。有的时候,会出现希望能够描述一个抽象的类,这个类不是为了生成对象,只是单纯的为了子类继承。
产生的原因:为了让其他类继承,不是创建对象【抽象类】
抽象类
【概念】如果讲一个类设计成抽象,则其他类可以继承,但是这个类不生成对象。
对于代码的规范
【定义】使用abstract关键字,修饰符
【规则】1)抽象类不能够被实例化,但是有构造器。(原因:创建子类对象的时候,一定会调用父类的构造器)
2)抽象类中可以有属性和方法,方法可以是非抽象方法,也可以是抽象方法
3)含有抽象方法的类一定是抽象类(普通非抽象类中不能含有抽象方法)
4)抽象类作为基类,表示被继承的类,所有继承了抽象类的子类()必须要实现(重写)抽象方法
【目的】
abstract class Teacher{
abstract void teacher();
}
class PythonTeacher extends Teacher{
void teacher() {
}
}
public class work {
public static void main(String[] args) {
}
}
抽象方法
抽象方法必须存在于抽象类中
【笔试陷阱】抽象类中,必须只能有抽象方法 错误
抽象类中,可以有非抽象的方法 对
抽象类中,可以全部都是非抽象方法 对
抽象类中,可以没有抽象方法 对
【实际应用中】一个抽象类中如果全部都是非抽象方法,则类的设计有问题,但是代码不出错
【抽象方法定义】使用abstract关键字声明方法,要求:没有方法体,连{}都没有(原因:在抽象类的抽象方法中实现方法,没有意义,因为子类无法调用到)
abstract class Teacher{
public abstract void teach();
}
class PythonTeacher extends Teacher{
public void teach(){
System.out.println("python授课");
}
}
class JavaTeacher extends Teacher{
public void teach(){
System.out.println("java授课");
}
}
public class T1 {
public void test(Teacher t){
t.teach();
}
public static void main(String[] args) {
T1 t=new T1();
JavaTeacher jt=new JavaTeacher();
PythonTeacher pt=new PythonTeacher();
t.test(jt);
t.test(pt);
}
}
【思考】
final 声明的类不能继承
abstract 声明的类为了继承
private和abstract:不行 方法对子类隐藏
static final和abstract:不可以
接口
背景:
java中继承关系——单继承
Person使用Phone,A下的[方法名],并不是真正的继承(没有想过继承)
Person对方法名进行重写
出现类接口概念,接口可以实现“多继承”—实现多个接口
单一 继承
多个 实现多个接口
【接口】特殊的抽象类,当抽象类下全部都是抽象方法,可以定义成借口(jdk1.8稍微更改,加入非抽象的方法)
接口:可以看成,方法都是抽象方法,接口没有构造器。(底层实现的时候“子类(实现类)创建时可以不未写完”)
接口的定义
1.语法:类class 接口interface
【修饰符】interface 接口名[extends 父接口名列表(多继承)]
【修饰符】接口可选择的就只有public:默认值就是public(跟类区分)
接口名:跟类名类似,首字母大写
extends:接口可以继承多个父级别的接口(接口的实现,接口的继承,都是多继承,多实现)
接口中的内容
常量【public】【static】【final】常量
抽象方法【public】【abstract】方法名();
以上【】中的内容都可以省略
jdk1.8中还可以加入非抽象的方法(静态方法、非静态方法——方法体)
default void fun1(){}
static void fun2(){}
实现接口
语法:创建类实现接口,实现关键字implements,多实现时使用,分隔开不同接口
定义一个学生的接口,上学抽象方法
Interface Student{
void gotoSchool();
}
class Student1 implements Student{
public void gotoSchool(){
System.out.print("走路上学");
}
}
class Student2 implements Student{
public void gotoSchool(){
System.out.print("骑车上学");
}
}
public class LZ{
public static void main(String[] args){
}
}
【思考】
从继承到接口,设计上,经历了几个层次?
继承: 父子关系,子类 继承父类,继承父类下的所有成员。(设计思想偏重在成员继承上)
抽象:父子关系,重点关注方法的实现。子类下要求必须重写父类的抽象方法(对继承重写语法规范),重点在于抽象方法实现
接口: A B C D 都同时去实现 Z 类下的方法,不 要求Z 有具体的实现,要求ABCD都使用相同的名字。
接口的设计理念跟抽象的设计理念相比:第一 ,抽象父子关系 第二,希望实现多继承
接口的关注点:在于多个接口下的方法,实现类,要去实现多个接口下的方法。
不关注父子关系。
接口的地位:规范,实现类之所以去实现接口:意味着实现类接受了接口中的规范(抽象方法)
interface School{
void gotoSchool();
}
interface Sport{
void swim();
}
class Student1 implements School,Sport{
public void gotoSchool(){
System.out.println("走路上学");
}
public void swim(){
System.out.println("去游泳池游泳");
}
}
class Student2 implements School,Sport{
public void gotoSchool(){
System.out.println("骑自行车上学");
}
public void swim(){
System.out.println("去游野泳");
}
}
class Student3 implements School{
public void gotoSchool(){
System.out.println("坐公交上学");
}
}
public class Day8_1_Interface {
public static void main(String[] args) {
School s1=new Student1();
Sport ss1=new Student1();
s1.gotoSchool();
ss1.swim();
}
}
实现类继承“继承”接口的成员
【继承】—【实现】
实现类对接口中的成员,还是可以有继承关系
涉及到的成员:常量、抽象方法、非抽象方法
【结论】实现类继承了接口的常量和抽象方法(调用的是自己实现的方法),非抽象的非静态方法不能继承,非抽象的静态方法不能继承(为了父类应用指向子类对象,对象不能够调用到编译期的内容(静态非抽象方法))
interface A{
int x=1;
void abstractFun();
}
接口继承接口
接口的的本质也是“”抽象类“所以也有继承关系
不同的地方在于:抽象类的继承是单继承
接口的继承是多继承(原因:接口的实现设计思想本身就是为了更多的重写方法,调用到重写接口方法)
将接口设计成多继承的,实现类可以实现更多方法
语法:子接口 extends 父接口1,父接口2…
一个实现类如果继承了一个接口,他就必须实现这个接口以及这个接口上的所有父类接口的抽象方法
interface X{
int a=1;
void m();
}
interface Y{
int b=2;
void n();
}
interface Z extends X,Y{
int c=a+b
}
class Zimpl implements Z{
public void m(){}
public void n(){}
//只要在zimpl能够调用m和n,那就说明Z继承X和Y成功了
}
【思考】如果两个父接口中都有完全相同的m方法,那么子接口继承的是哪个方法?实现类中实现的是哪个方法呢?
继承只需要继承一个,实现类中只要实现其中一个即可
原因:接口中根本没有对方法进行实现,所以实现类中,继承接口中,继承哪一个,实现哪一个都无所谓
真正实现的过程中,这样的设计师不合理的
interface X{
void m();
}
interface Y{
void m();
}
interface Z extends Y,X{
}
class Zimpl implements Z{
public void m(){}
//只要在zimpl能够调用m和n,那就说明Z继承X和Y成功了
}
空接口
实现了空接口的实现类,不是什么都不能调用,至少可以调用object下的内容
interface Empty{}
class EmptyImpl extend Object implements Empty{
//是不是意味着这个类什么都不能调用
}
再看jdk1.8的新功能
1.8之前,不允许接口中有非抽象的方法
1.8之后允许接口中有非抽象的方法
【为什么】接口,下包含抽象方法,要求实现类来实现,接口,高
java本身也有很多的接口,java本身自己也要更新
接口也有可能更新
interface Car{
void start();
void stop();
default void fly(){};
}
class CarImpll implements Car{
public void start(){
}
}
1.8之前怎么解决
interface Car{
void start();
void stop();
}
class CarImpll implements Car{
public void start(){
}
public void stop(){
}
}
接口和抽象类之间的区别
属性:接口必须要求是常量,抽象类没有要求
构造器:接口没有构造器,抽象类有构造器
普通方法:1.8之前必须是抽象,可以有非抽象
抽象类:可以全部是抽象方法
子类(实现类):接口多重实现,抽象类单一继承
继承:注重父子关系
抽象:注重父子关系,也注重重写
接口:只注重重写
枚举类型
背景:1.5之后产生一种类型 本质也是class 跟interface一样
需求:需要使用到很多的常量
状态 班级:正常、停用
院系:正常、停用
正常:0 停用:1
已注册0 未注册1 注册未通过2
为了规范常量的代码
枚举类型的定义
使用emup关键字就可以声明一个枚举类型的java文件、
内部直接声明常量名
public enum Align{
LEFT,CENTER,RIGHT
}
//引用端
public class Lz{
public void test(Align v);
public static void main(String[] args){
// if(v==0){调用出错,类型不匹配。规范代码
if(v==Align.LEFT){
System.out println();
}
}
}
switch对于枚举类型的支持
原因:case后面必须放常量
public class Lz{
public void test(){
Align align.CENTER;
switch(align){
case LEFT:
System.out.println("左对齐");
break;
case CENTER:
System.out.println("中间对齐");
break;
}
}
}
枚举的规则
【枚举类型的优势】通过枚举类型,我们实现了对于常量类型控制,调用段只能使用指定的常量,枚举类型是安全的类型,调用者无法自己篡改类型
【规则】
1)枚举默认类型的构造器是私有的构造器
2)枚举类型不可以再继承其他的类,本质上单继承了Enum,隐式继承
3)枚举类型可以实现接口(只做了解,作用,对于每个枚举类型的常量都可以实现接口,通过调用枚举类型,就可以调用到每个枚举下的方法,跟每个子类调用自己的方法原理是一样的)
public enum Align implements Introduce{
LEFT{
public void show(){
System.out.println("CENTER常量的show");
}
},CENTER{
public void show(){
System.out.println("CENTER常量的show");
}
},RIGHT{
public void show(){
System.out.println("CENTER常量的show");
}
};
public static void main(String[] args){
for(Align a:Align.values()){
a.show();
}
}
}
interface Introduce{
void show();
}