instanceof
运算符
1.含义:判别对象是否是某个引用型的实例
2.E instanceof RefType
Animal a=new Animal();Dog d=new Dog();//a,aDog是Animal类型,d是Dog类型
Animal aDog=new Dog()//有aDog instanceof Animal;aDog instanceof Dog均为true
//有aDog instanceof Cat;a instanceof Dog均为false
//有d instanceof Cat编译错,d不能强制转换为Cat类型
//有null instanceof Cat为false,因为null不是任何引用型的实例
抽象类
抽象类
1.一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
2.抽象类不能实例化对象, 只有抽象类的非抽象子类可以创建对象。
3.类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
4.抽象类必须被继承,才能被使用。
5.抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
抽象方法
1.定义:无方法体,用abstract修饰的方法。
2.作用:是一种“契约”,超类提供契约(抽象方法),要求该超类的子类必须实现该契约(重写抽象方法,为抽象方法补上方法体),否则,如果没有实现该抽象方法,该子类必须是抽象类(无法创建对象)
3.构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
public abstract class Employee
{
private String name;
private String address;
private int number;
public abstract double computePay();
//其余代码
}
//如果Salary类继承了Employee类,那么它必须实现computePay()方法:
public class Salary extends Employee
{
private double salary; // Annual salary
public double computePay()
{
System.out.println("Computing salary pay for " + getName());
return salary/52;
}
//其余代码
}
注意:
*abstract不能修饰构造方法
*abstract不能与final,static同时使用
接口
一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。 借助接口,可以实现不同对象的耦合。
语法约束
1.变量默认:public(公开) static(唯一性) final(不可更改)。
2.方法默认:public abstract,不可更改。
interface Test1{
int x=0; //正确 前面有默认的public static final
void f(); //正确 前面有默认的public abstract
int y; //错误,没有赋值
protected int y; //错误,不能用protected修饰
private void h();//错误,不能用private修饰
void g(){;} //错误,不能有方法体
}
接口与类的关系
- 一个接口可以有多个方法
- 类实现接口的抽象方法
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
接口与类的区别
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
抽象类和接口的区别
- 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
- 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
声明语法
interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
实例
interface Animal {
public void eat();
public void travel();
}
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
重写接口中声明的方法时,需要注意以下规则:
- 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
- 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
- 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
接口的继承
1.接口的继承使用extends关键字,子接口继承父接口的方法。
2.接口的多继承: extends关键字只需要使用一次,在其后跟着继承接口
public interface Hockey extends Sports, Event
public interface Sports
{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
public interface Football extends Sports
{
public void homeTeamScored(int points);
public void visitingTeamScored(int points);
public void endOfQuarter(int quarter);
}//实现Football接口的类需要实现五个方法,其中两个来自于Sports接口
public interface Hockey extends Sports
{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}//Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,实现Hockey接口的类需要实现六个方法。
3.接口多继承存在的问题
- 菱形继承:如下图所示B、C继承A;D继承B、C,D类中x的类型不能确定
-
接口冲突现象
interface A{int x=10;} interface B{double x=2;} interface C extends A,B{;} //C里面有两个x class D implements C{;} //上述代码虽编译正确,加入下列代码会引发编译错误 D d=new D(); System.out.println(d.x)//编译错误
初始化块
1.初始化块:在类中独立于成员方法之外的代码段。
◆无名、无参、无返回值。
◆被static修饰为静态初始化块,否则为实例块。
2.初始化块的执行遵循以下规则:
◆静态块先于实例块,实例块先于构造函数;
◆多个实例块/静态块的执行顺序同其出现次序;
◆静态块在类初次加载时执行,仅执行一次。
class TestBlock{ TestBlock (int x){System,out.print("1== ");} TestBlock (){System,out.print("2== ");} static {System,out.print("Static 3== ");}//静态初始化块 {System,out.print("4== ");}//实例初始化块 {System,out.print("5== ");}//实例初始化块 static {System,out.print("Static 6== ");}//静态初始化块 } class{ public static void main(String args[]){ System,out.print("ppppp== "); new TestBlock(); new TestBlock (99); } } //运行结果:ppppp== Static 3== Static 6== "4== 5== 2== 4== 5== 1== /*总结:初始化块的作用,就是为了初始化 从结果看,静态块先于实例块,且仅仅执行一次 (即在类加载时执行) 每次构造对象,都要执行先执行实例块,再执行构造函数*/
包
区别类名的命名空间 ,用于将类分门别类的管理,且避免类名冲突(即重名)。
1.声明包:一个java
源文件只能声明一个包,用于指明编译后.class文件存储的位置。package语句只能放在第一句。
2.导入包:导入后,可以直接使用类名A。未导入则必须使用全名,如a.b.x.A a=new a.b.x.A();
,若导入,使用 A a=new A()
即可。
3.包的作用:把不同的 java
程序分类保存,更方便的被其他 java
程序调用。
4.import java.util.*;
– 按需导入,会影响编译速度,不影响执行速度。
5.无名包:若未声明包,则编译后产生的.class文件自动放置于无名包。无名包中的类,没有包名,故无法被导入。只能直接拷贝到目录或包中使用。
类的权限
两种权限:public和缺省
**跨包访问:**只能访问外包的public类。
package a.b.x;
public class A {
public void fa() {;}
}
class B {
public void fb() {;}
}
-----------------------------------------
package a.b.y; import a.b.x.A;
public class C {
public void fc() {
A a=new A(); a.fa(); //编译正确
//a.b.x.A a=new a.b.x.A(); a.fa(); //正确
//a.b.x.B b=new a.b.x.B(); //编译错
}
}
class D {
public void fd() {
A a=new A(); a.fa(); //编译正确
//a.b.x.A a=new a.b.x.A(); a.fa(); 正确
//a.b.x.B b=new a.b.x.B(); //编译错
}
}
//C、D中只能访问A,不能访问B
类中成员的权限
1.对同一类而言,权限没有意义:成员间可任意访问,不受权限制约。
2.对同一包中的类A和B,A不能访问B中的私有部分,其它均可访问;
3. 跨包访问的要求极为苛刻,要求:只能访问public类的public成员。
4. 拓展:允许包外的子孙访问自己的protected成员。
package X;
public class A{
public int x1;
protected int x2;
int x3;
private int x4;
}
class B{
public int y1;
protected int y2;
int y3;
private int y4;
}
----------------------------------
package Y;
public class C{
void h(){
D d=new D();
d.x2=5;//编译错
}
}
class D extends A
{
void h(){
A a=new A();
x2=6; //正确
a.x2=5;//编译错,D继承的x2,依旧隶属X包,有保护权限,故编译错。
}
}
void f()//将f()放在C、D中,f()中的哪些操作可能成功,哪些必定会失败?
{ A a=new A();
a.x1=1; a.x2=2; a.x3=3;
B b=new B();
b.y1=1; b.y2=2; b.y3=2;
}
//放在C中 只能访问x1;放在D中,只能访问x1,x2