赞
踩
final
表示不可改变的含义
如下代码:
public class FinalTest01 {
public static void main(String[] args) {
}
}
final class A{
public void test01(){
}
}
//不能继承 A,因为 A 采用 final 修饰了
class B extends A{
public void test01(){
}
}
编译报错:
如下代码:
public class FinalTest02 { public static void main(String[] args) { } } class A1{ //采用final修饰的方法 public final void test01(){ } } class B1 extends A1{ //覆盖父类的方法,改变其行为 //因为父类的方法是 final 修饰的,所以不能覆盖 public void test01(){ } }
编译报错:
如下代码:
public class FinalTest03 {
private final long id = 24353465456575677L;
public static void main(String[] args) {
id = 454657686787987978L;
}
}
编译报错:
如下代码:
public class FinalTest04 {
// 如果是 final 修饰的变量必须初始化
private final long id;
public static void main(String[] args) {
int i;
// 局部变量如果要使用也必须初始化
System.out.println(i);
}
}
编译报错:
如下代码;
public class FinalTest05 { public static void main(String[] args) { Person p1 = new Person(); //可以赋值 p1.name = "张三"; System.out.println(p1.name); final Person p2 = new Person(); p2.name = "李四"; System.out.println(p2.name); //不能编译通过 //p2 采用 final 修饰,主要限制了 p2 指向堆区中的地址不能修改(也就是p2 只能指向一个对象) //p2 指向的对象的属性是可以修改的 p2 = new Person(); p2.name = "王五"; } } class Person { String name; }
编译报错:
如果final修饰实例变量,则系统不再会给该实例变量赋默认值【因为这样的话,该实例变量就无法再被赋值】,此时,必须由程序员手动赋值!!!
如下代码:
class Person {
final String name;
}
编译报错:
手动赋值要么在声明后直接=,要么在构造方法中赋值!
class Person {
final String name="Wang"; //可以,不报错
}
class Person {
final String name;
public Person(){
this.name = "Wang"; //也可以实际上与声明时直接=是等价的,上面也是在构造方法执
//行时才执行,声明时只是开辟空间,没有立刻赋值
}
}
一个小回顾:实例变量在什么时候进行赋默认值(初始化)?
=>在构造方法执行过程中(new 的时候赋值!)
注意:一般final会与static联合使用,这样的变量为常量【其一般也是public的】。
看以前示例中的 Animal、Cat 和 Dog,从我们使用的角度来看要对 Cat 和 Dog 进行实例化,Person 中主要包含了一些公共的属性和方法,而 Animal 我们通常不会实例化,所以我们可以把它定义成抽象的:
abstract
关键字定义的类就是抽象类,采用 abstract 关键字定义的方法就是抽象方法;图形的例子:
在java中凡是没有方法体的方法都是抽象方法吗?
=>不对,Object类中就有很多方法没有方法体,都是以’;'结尾的,但是他们都不是抽象方法,例如public native int hashcode();
这个方法就没有用abstract
修饰,其底层调用的是C++的动态链接库,其中native
表示调用JVM本地程序。
public class AbstractTest01 { public static void main(String[] args) { //不能实例化抽象类 //抽象类是不存在,抽象类必须有子类继承 // Person p = new Person(); //以下使用是正确的,因为我们 new的是具体类 Person p1 = new Employee(); p1.setName("张三"); System.out.println(p1.getName()); } } //采用 abstract 定义抽象类 //在抽象类中可以定义一些子类公共的方法或属性 //这样子类就可以直接继承下来使用了,而不需要每个 //子类重复定义 abstract class Person { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } //此方法各个子类都可以使用 public void commonMethod1() { System.out.println("---------commonMethod1-------"); } } class Employee extends Person {} class Student extends Person {}
public class AbstractTest02 { public static void main(String[] args) { Person01 teacher = new Teacher(); teacher.setName("Li"); System.out.println(teacher.getName()); teacher.commonMethod(); teacher.abstractMethod(); } } abstract class Person01{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // 此方法各个子类都可以使用 public void commonMethod(){ System.out.println("----commonMethod----"); } //抽象方法,子类必须实现 //如果有一个方法为抽象的,那么此类必须为抽象的 public abstract void abstractMethod(); } class Teacher extends Person01 { @Override public void abstractMethod() { System.out.println("对Person01抽象方法的实现!"); } }
运行结果:
public class AbstractTest03 { public static void main(String[] args) { // 此时Doctor类也是抽象的,不能再new // Person doctor = new Doctor(); } } abstract class Person{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // 此方法各个子类都可以使用 public void commonMethod(){ System.out.println("----commonMethod----"); } //抽象方法,子类必须实现 //如果有一个方法为抽象的,那么此类必须为抽象的 public abstract void abstractMethod(); } abstract class Doctor extends Person { //再次声明该方法为抽象的 public abstract void abstractMethod(); }
如下代码;
final abstract class Person{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } // 此方法各个子类都可以使用 public void commonMethod(){ System.out.println("----commonMethod----"); } //抽象方法,子类必须实现 //如果有一个方法为抽象的,那么此类必须为抽象的 public abstract void abstractMethod(); }
编译报错:
abstract class Animal{
//抽象类可以没有抽象方法,其依旧是抽象类
// 普通方法,此方法各个子类都可以使用
public void commonMethod(){
System.out.println("----commonMethod----");
}
}
public class AbstractTest04 { public static void main(String[] args) { Book paperBook = new PaperBook("解忧杂货店", 486); System.out.println(paperBook.getName()); System.out.println(((PaperBook) paperBook).getPageNum()); } } //抽象书类 abstract class Book{ private String name; //书名 public String getName() { return name; } public void setName(String name) { this.name = name; } //抽象类可以定义构造方法 public Book(String name) { this.name = name; } } //纸质书类 class PaperBook extends Book{ private int pageNum; //页数 public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public PaperBook(String name, int pageNum) { super(name); this.pageNum = pageNum; } }
接口我们可以看作是抽象类的一种特殊情况,在接口中只能定义抽象的方法和常量
interface
声明;public abstract
的,不能更改;public static final
类型的,不能更改,所以必须显式地初始化;implements
关键字;abstract class 抽象类类名 implements 接口名{}
;ClassCastException
异常;Object
。如下代码:
public class InterfaceTest01 { public static void main(String[] args) { } } //采用 interface 定义接口 //定义功能,没有实现 //实现委托给类实现 interface StudentManager { //正确,默认为 public abstract 等同 public abstract void addStudent(int id, String name); void addStudent(int id, String name); //正确,可以加入 public 修饰符,此种写法较多 public void delStudent(int id); //正确,可以加入 abstract,这种写法比较少 public abstract void modifyStudent(int id, String name); //编译错误,因为接口就是让其他人实现 //采用 private 就和接口原本的定义产生矛盾了 private String findStudentById(int id); }
编译报错:
如下代码:
public class InterfaceTest02 { public static void main(String[] args) { //不能修改,因为是 final 的 StudentManager02.YES = "YES"; System.out.println(StudentManager02.NO); } } interface StudentManager02{ //正确,默认加入 public static final String YES = "yes"; //正确, 开发中一般就按照下面的方式进行声明 public static final String NO = "no"; //错误,必须赋值,因为是 final 的 int ON; //错误,不能采用 private 声明 private static final int OFF = -1; }
编译报错:
如下代码;
public class InterfaceTest03 {
public static void main(String[] args) {
//接口是抽象类的一种特例,只能定义方法和变量,没有实现,所以不能实例化
StudentManager03 studentManager03 = new StudentManager03();
}
}
interface StudentManager03{
void addStudent(int id,String name);
}
编译报错:
如下代码:
public class InterfaceTest04 { public static void main(String[] args) { } } interface inter1{ public void method1(); public void method2(); } interface inter2{ public void method3(); } //接口可以继承 interface inter3 extends inter1{ public void method4(); } //接口不能实现接口 //接口只能被类实现 interface inter4 implements inter2{ }
编译报错;
如下代码:
public class InterfaceTest05 { public static void main(String[] args) { //Iter1Impl 实现了 Inter1 接口 //所以它是 Inter1 类型的产品 //所以可以赋值 Inter1 inter1 = new Inter1Impl(); inter1.method1(); //Iter1Impl123 实现了 Inter1 接口 //所以它是 Inter1 类型的产品 //所以可以赋值 Inter1 inter123 = new Iter1Impl123(); inter123.method2(); //可以直接采用 Iter1Impl 来声明类型 //这种方式存在问题 //不利于互换,因为面向具体编程了 Inter1Impl interImpl = new Inter1Impl(); interImpl.method1(); //不能直接赋值给 iter1Impl //因为 Iter1Impl123 不是 Iter1Impl 类型 // iterImpl = new Iter1Impl123(); } } //定义接口 interface Inter1{ public void method1(); public void method2(); public void method3(); } //接口中的方法必须全部实现 class Inter1Impl implements Inter1 { @Override public void method1() { System.out.println("method1"); } @Override public void method2() { System.out.println("method1"); } @Override public void method3() { System.out.println("method1"); } } class Iter1Impl123 implements Inter1 { @Override public void method1() { System.out.println("method1_123"); } @Override public void method2() { System.out.println("method2_123"); } @Override public void method3() { System.out.println("method3_123"); } } abstract class IterImpl456 implements Inter1 { @Override public void method1() { System.out.println("method1_123"); } @Override public void method2() { System.out.println("method2_123"); } //再次声明为抽象方法 abstract public void method3(); }
编译报错:
注释上述报错行后运行结果:
public class InterfaceTest06 { public static void main(String[] args) { //可以采用 Inter1 定义 Inter01 inter01 = new InterImpl01(); inter01.method1(); ((InterImpl01) inter01).method2(); //调用非实现Inter01接口的方法必须进行强转 //可以采用 Inter2 定义 Inter02 inter02 = new InterImpl01(); inter02.method2(); //可以采用 Inter3 定义 Inter03 inter03 = new InterImpl01(); inter03.method3(); } } interface Inter01{ public void method1(); } interface Inter02{ public void method2(); } interface Inter03{ public void method3(); } //粗粒度 /* interface inter{ public void method1(); public void method2(); public void method3(); } */ //实现多个接口,采用逗号隔开 //这样这个类就拥有了多种类型 //等同于现实中的多继承 //所以采用 java 中的接口可以实现多继承 //把接口粒度划分细了,可以使功能定义的含义更明确 //可以采用一个大的接口定义所有功能,替代多个小的接口, //但这样定义功能不明确,粒度太粗了 class InterImpl01 implements Inter01,Inter02,Inter03{ @Override public void method1() { System.out.println("******method1******"); } @Override public void method2() { System.out.println("******method2******"); } @Override public void method3() { System.out.println("******method3******"); } }
运行结果:
由上3.6即可以看出,也可看如下例子:
interface A{ 其中有方法m1 } interface B{ 其中有方法m2 }
情况1:若有类C:class C implementsA{}
若此时有:A a =new C(); B b = (B)a;//C与B没有关系,出现运行异常
情况2:若有类C:class C implements A,B{}
若此时有:A a =new C(); B b = (B)a;//为了调用m2(),进行接口转型,
可以运行 b.m2();//此时只能调用m2()方法,不能调用 m1()方法,要向下转型成C c = (C)a才可以。
对于以上不用太纠结,反正也没啥用,只要养成好习惯:向下转型前用if
+instanceof
判断即可。
情况1具体代码:
public class InterfaceTest07 { public static void main(String[] args) { A a = new C(); a.m1(); B b = (B)a; //C 和 B 没有关系,出现运行时异常 } } interface A{ public void m1(); } interface B{ public void m2(); } class C implements A{ @Override public void m1() { System.out.println("=========m1=========="); } }
运行结果:
情况2具体代码:
public class InterfaceTest07 { public static void main(String[] args) { A a = new C(); a.m1(); B b = (B)a; //为了调用m2()进行接口转型 b.m2(); } } interface A{ public void m1(); } interface B{ public void m2(); } class C implements A,B{ @Override public void m1() { System.out.println("=========m1=========="); } @Override public void m2() { System.out.println("=========m2=========="); } }
运行结果:
ClassCastException
异常另外,类在强制转换过程中,如果父类 引用转换成接口类型,那么父类和接口之间不需要存在实 现关系,也可以转换,java语法时允许的。(前提父类引用中实际保存的子类引用所指对象有实现该接口!否则运行阶段还是会有类型转换异常)
语法:class 类名 extends 抽象类名 implements 接口名{}
只能extends在前,不能class 类名 implements 接口名 extends 抽象类名()
如下代码:
public class InterfaceTest08 { public static void main(String[] args) { E e = new F(); e.m2(); ((F) e).m1(); //强转成子类型才可以调用m1 D d = new F(); d.m1(); ((F) d).m2(); //强转成子类型才可以调用m2 } } interface D{ public void m1(); } abstract class E{ abstract public void m2(); } class F extends E implements D { @Override public void m1() { System.out.println("----------m1----------"); } @Override public void m2() { System.out.println("----------m2----------"); } }
运行结果:
在 java 中接口其实᧿述了类需要做的事情,类要遵循接口的定义来做事,使用接口的本质好处可以归纳为:
接口解耦合是解开的是调用者和实现者之间的耦合,调用者面向接口调用, 实现者面向接口编写实现。这样在开发时,项目组可以为围绕接口开发,根据接口将项目分成不同的模块,同步进行,提高开发效率。
示例:完成学生信息的增删改操作,系统要求适用于多个数据库,如:适用于 Oracle 和 MySQL。
UML,统一建模语言:
代码:
//Oracle 的实现
public class StudentOracleImpl {
public void add(int id, String name) {
System.out.println("StudentOracleImpl.add()");
}
public void del(int id) {
System.out.println("StudentOracleImpl.del()");
}
public void modify(int id, String name) {
System.out.println("StudentOracleImpl.modify()");
}
}
Mysql 的实现
public class StudentMysqlImpl {
public void addStudent(int id, String name) {
System.out.println("StudentMysqlImpl.addStudent()");
}
public void deleteStudent(int id) {
System.out.println("StudentMysqlImpl.deleteStudent()");
}
public void udpateStudent(int id, String name) {
System.out.println("StudentMysqlImpl.udpateStudent()");
}
}
调用以上两个类完成向 Oracle 数据库和 Mysql 数据存储数据:
public class StudentManager {
public static void main(String[] args) {
//对 Oracle 数据库的支持
StudentOracleImpl studentOracleImpl = new StudentOracleImpl();
studentOracleImpl.add(1, "张三");
studentOracleImpl.del(1);
studentOracleImpl.modify(1, "张三");
//需要支持 Mysql 数据库
StudentMysqlImpl studentMysqlImpl = new StudentMysqlImpl();
studentMysqlImpl.addStudent(1, "张三");
studentMysqlImpl.deleteStudent(1);
studentMysqlImpl.udpateStudent(1, "张三");
}
}
以上代码不能灵活的适应需求,当需求发生改变需要改动的代码量太大,这样可能会导致代码的冗余,另外可能会导致项目的失败,为什么会导致这个问题,在开发中没有考虑到程序的扩展性,就是一味的实现,这样做程序是不行的,所以大的项目比较追求程序扩展性,有了扩展性才可以更好的适应需求。
代码:
public class InterfaceTest09 { public static void main(String[] args) { /* IStudent istudent = new Student4OracleImpl(); IStudent istudent = new Student4MysqlImpl(); istudent.add(1, "张三"); istudent.del(1); istudent.modify(1, "张三"); */ //进一步简化,创建doCrud()方法 doCrud(new Student4OracleImpl()); doCrud(new Student4MysqlImpl()); } //此种写法没有依赖具体的实现 //而只依赖的抽象,就像你的手机电池一样:你的手机只依赖电池(电池是一个抽象的事物), //而不依赖某个厂家的电池(某个厂家的电池就是具体的事物了) //因为你依赖了抽象的事物,每个抽象的事物都有不同的实现 //这样你就可以利用多态的机制完成动态绑定,进行互换,是程序具有较高的灵活 //我们尽量遵循面向接口(抽象)编程,而不要面向实现编程 public static void doCrud(IStudent istudent) { istudent.add(1, "张三"); istudent.del(1); istudent.modify(1, "张三"); } //以下写法不具有扩展性 //因为它依赖了具体的实现 //建议不要采用此种方法,此种方案是面向实现编程,就依赖于具体的东西了 /* public static void doCrud(Student4OracleImpl istudent) { istudent.add(1, "张三"); istudent.del(1); istudent.modify(1, "张三"); } */ } interface IStudent{ public void add(int id, String name); public void del(int id); public void modify(int id, String name); } class Student4OracleImpl implements IStudent { public void add(int id, String name) { System.out.println("Student4OracleImpl.add()"); } public void del(int id) { System.out.println("Student4OracleImpl.del()"); } public void modify(int id, String name) { System.out.println("Student4OracleImpl.modify()"); } } class Student4MysqlImpl implements IStudent { public void add(int id, String name) { System.out.println("Student4MysqlImpl.add()"); } public void del(int id) { System.out.println("Student4MysqlImpl.del()"); } public void modify(int id, String name) { System.out.println("Student4MysqlImpl.modify()"); } }
运行结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。