继承弊端:打破了封装性。
final关键字:
1,final是一个修饰符,可以修饰类,方法,变量。
2,final修饰的类不可以被继承。
3,final修饰的方法不可以被覆盖。
4,final修饰的变量是一个常量,只能赋值一次。
为什么要用final修饰变量。其实在程序如果一个数据是固定的,
那么直接使用这个数据就可以了,但是这样阅读性差,所以它该数据起个名称。
而且这个变量名称的值不能变化,所以加上final固定。
写法规范:常量所有字母都大写,多个单词,中间用_连接。
抽象类:
抽象:笼统,模糊,看不懂!不具体。
特点:
1,方法只有声明没有实现时,该方法就是抽象方法,需要被abstract修饰。
抽象方法必须定义在抽象类中。该类必须也被abstract修饰。
2,抽象类不可以被实例化。为什么?因为调用抽象方法没意义。
3,抽象类必须有其子类覆盖了所有的抽象方法后,该子类才可以实例化。
否则,这个子类还是抽象类。
1,抽象类中有构造函数吗?
有,用于给子类对象进行初始化。
2,抽象类可以不定义抽象方法吗?
可以的。 但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类。
通常这个类中的方法有方法体,但是却没有内容。
abstract class Demo
{
void show1()
{}
void show2()
{}
}
3,抽象关键字不可以和那些关键字共存?
private 不行 ,private进行了封装
static 不行 ,通过类名.方法调用没有意义
final 不行,final代表最终的,不能被重写
4,抽象类和一般类的异同点。
相同点:
抽象类和一般类都是用来描述事物的,都在内部定了成员。
不同:
1,一般类有足够的信息描述事物。
抽象类描述事物的信息有可能不足。
2,一般类中不能定义抽象方法,只能定非抽象方法。
抽象类中可定义抽象方法,同时也可以定义非抽象方法。
3,一般类可以被实例化。
抽象类不可以被实例化。
5,抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化。
接口
定义接口使用的关键字不是class,是interface.
/*
对于接口当中常见的成员:而且这些成员都有固定的修饰符。
1,全局常量: public static final
2,抽象方法。public abstract
由此得出结论,接口中的成员都是公共的权限.
interface Demo
{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
}
类与类之间是继承关系,类与接口直接是实现关系。
接口不可以实例化。
只能由实现了接口的子类并覆盖了接口中所有的抽象方法后,该子类才可以实例化。
否则,这个子类就是一个抽象类。
修饰符 class 类名 extends 父类implements 接口1,接口2。。。
{类体部分 ,如果继承了抽象类,需要实现继承的抽象方法;要实现接口中的抽象方法}
interface QQ extends CC,MM//接口与接口之间是继承关系,而且接口可以多继承。
{
void function();
}
class WW implements QQ
{
//覆盖3个方法。
public void show(){}
public void method(){}
public void function(){}
}
抽象类和接口的异同点:
相同点:
都是不断向上抽取而来的。
不同点:
1,抽象类需要被继承,而且只能单继承。
接口需要被实现,而且可以多实现。
2,抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。
接口中只能定义抽象方法,必须由子类去实现。
3,抽象类的继承,是is a关系,在定义该体系的基本共性内容。
接口的实现是 like a 关系,在定义体系额外功能。
多态
对象的多态性。
class 动物
{}
class 猫 extends 动物
{}
class 狗 extends 动物
{}
猫 x = new 猫();
动物 x = new 猫();//一个对象,两种形态。
猫这类事物即具备者猫的形态,又具备着动物的形态。
这就是对象的多态性。
简单说:就是一个对象对应着不同类型.
多态在代码中的体现:
父类或者接口的引用指向其子类的对象。
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
多态的弊端:
前期定义的内容不能使用(调用)后期子类的特有内容。
多态的前提:
1,必须有关系,继承,实现。
2,要有覆盖。
Animal a = new Cat(); //自动类型提升,猫对象提升了动物类型。但是特有功能无法访问。
作用就是限制对特有功能的访问。
专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。
如果还想用具体动物猫的特有功能。
你可以将该对象进行向下转型。
Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法。
c.eat();
c.catchMouse();
注意:对于转型,自始自终都是子类对象在做着类型的变化。
public static void method(Animal a)
{
a.eat();
if(a instanceof Cat)//instanceof:用于判断对象的具体类型,只能用于引用数据类型判断
//通常在向下转型前用于健壮性的判断, 如果传入了其他的东西就不能调用
{
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d = (Dog)a;
d.lookHome();
}
多态时,
成员的特点:
1,成员变量。
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过,没有,编译失败。
运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量。
简单说:编译和运行都参考等号的左边。哦了。
作为了解。
2,成员函数(非静态)。
编译时:参考引用型变量所属的类中的是否有调用的函数。有,编译通过,没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数。
简单说:编译看左边,运行看右边。
因为成员函数存在覆盖特性。
3,静态函数。
编译时:参考引用型变量所属的类中的是否有调用的静态方法。
运行时:参考引用型变量所属的类中的是否有调用的静态方法。
简单说,编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用即可。
内部类
内部类访问特点:
1,内部类可以直接访问外部类中的成员。
2,外部类要访问内部类,必须建立内部类的对象。
一把用于类的设计。
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就是还有的事物定义成内部类来描述。
class Outer
{
private static int num = 31;
class Inner// 内部类
{
void show()
{
System.out.println("show run..."+num);
}
/*static void function()//如果内部类中定义了静态成员,该内部类也必须是静态的
{
System.out.println("function run ...."+num);
}
*/
}
public void method()
{
Inner in = new Inner();
in.show();
}
}
在类的外部如何访问内部类对象?
对于非静态内部类
①先创建外部类对象,然后再创建内部类对象
OuterClass oc=new OutClass();
InnerClass ic=oc.new InnerClss();
ic.test();
class InnerClassDemo
{
public static void main(String[] args)
{
②Outer out = new Outer();
out.method();
这是创建一个方法访问
③直接访问外部类中的内部类中的成员。
Outer.Inner in = new Outer().new Inner();
in.show();
静态内部类:内部使用static来修饰,所以创建该类的对象可以没有外部类对象
如果内部类是静态的。 相当于一个外部类
Outer.Inner in = new Outer.Inner();
in.show();
如果内部类是静态的,成员是静态的。
Outer.Inner.function();
}
}
为什么内部类能直接访问外部类中成员呢?
那是因为内部类持有了外部类的引用。 外部类名.this
class Outer
{
int num = 1;
class Inner
{
int num = 2;
void show()
{
int num = 3;
System.out.println(num);//3
System.out.println(this.num);//2
System.out.println(Outer.this.num);//1
如果外部成员变量是int a=1,这里直接写就行,即名称不一样的时候上面这样写
}
}
void method()
{
new Inner().show();//匿名对象
}
}
class InnerClassDemo2
{
public static void main(String[] args)
{
new Outer().method();
}
}
注意:静态内部类中的方法不能访问外部内的非静态成员
内部类可以存放在局部位置上。
内部类在局部位置上只能访问局部中被final修饰的局部变量。
class Outer
{
int num = 3;
Object method()
{
final int x = 9;
class Inner
{
public String toString()
{
return "show ..."+x;
}
}
匿名内部类。就是内部类的简写格式。
在类的内部直接创建一个接口的实现类对象
必须有前提:
内部类必须继承或者实现一个外部类或者接口。
匿名内部类:其实就是一个匿名子类对象。
格式:new 父类or接口(){子类内容}
abstract class Demo
{
abstract void show();
}
class Outer
{
int num = 4;
/* 正常情况
class Inner extends Demo
{
void show()
{
System.out.println("show ..."+num);
}
}
*/
public void method()
{
//new Inner().show();
new Demo()//匿名内部类。 直接内容写进去
{
void show()
{
System.out.println("show ........"+num);
}
}.show(); //可以调用,也可以不调用
}
}
class InnerClassDemo4
{
public static void main(String[] args)
{
new Outer().method();
}
}
通常的使用场景之一:
当函数参数是接口类型时,而且接口中的方法不超过三个。
可以用匿名内部类作为实际参数进行传递?
不是太懂,参见day10 InnerClassDemo5.java
class Outer
{
void method()
{
Object obj = new Object() //匿名内部的特征就是直接在()后写内部内容
{
public void show()
{
System.out.println("show run");
}
};
obj.show();//因为匿名内部类这个子类对象被向上转型为了Object类型。
//这样就不能在使用子类特有的方法了。
}
}
class InnerClassDemo6
{
public static void main(String[] args)
{
new Outer().method();
}
}
Eg:
New IplayGame(){
Public void playGame(){
Sysout(用匿名内部类实现接口)}
}.playGame();
也可以在类的内部这样写:
IplayGame ip= new iplayGame(){
Public void playGame(){
Sysout(“使用匿名内部类实现接口”)}};
Ip.playGame();//通过这样访问这个方法
Object类:
它是所有类的根父类
- Object类的变量可以指向任何类型的对象
- Object是不断抽取而来,具备着所有对象都具备的共性内容。
- Objict的方法,参数类型是Object类型,所以可以传入任何参数
默认为:Object obj=new person()
==和equals:
1.==:对于引用类型,表叫俩个对象的内存地址是否相同,要求俩边对象是类型兼容的,若不兼容,则编译出错
2.Object类的equals方法:原义是比较俩个对象的内存地址是否相同,可以传入任何对象,通常情况我们
是比较俩个参数的值是否相同,所以可以根据业务的需要重写该方法,步骤:
Public boolean equals(object obj)
①检验传入的为person类型,若不是,直接返回false
If(!(Obj instanceof person))
Return false;
②若是person类型,则先进行强制转换
Person person=(person)obj
③比较name和age
If(name.equals(person.name)&&age==person.age)
Return ture;
Return false;
Tostring()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址(哈西码)
在进行String与其他类型数据连接操作时,自动调用tostring()方法
Date now=new date();
Sysout(now)相当于sysout(now.tostring())
输出的是[email protected]
一般开发时重写该方法
S1=”hello”;
Sysout(s1)
System.out.println(p1.toString());//[email protected]
hashCode方法
当equals方法重写时,通常有必要重写hashcode方法 ,因为内容相同,地址也得相同,才能叫一样
getClass方法
获取当前对象所属的字节码文件对象
Class clazz1 = p1.getClass();
Class clazz2 = p2.getClass();
System.out.println(clazz1==clazz2);
System.out.println(clazz1.getName());
getClass().getName()获取字节码文件对象的名称:person
getClass().method()获取字节码文件对象的方
System.out.println(p1.getClass().getName()+"$"+Integer.toHexString(p1.hashCode()));//[email protected]
Integer.toHexString:10进制转换16进制,工作时经常用,因为能短点