Java学习笔记————面向对象(高级)
1. 面向对象(高级)
1.1 抽象类(重点)
抽象类:包含一个抽象方法的类称为抽象类,抽象方法是只声明而为实现的方法,不包含方法主体。所有的抽象方法必须用abstract关键字声明;所有的抽象类也必须用关键字abstract声明。
abstract class A{ public abstract void fun(){ } } public class AbstractDemo01{ public static void main(String[] args){
} } |
abstract class A{ public abstract void fun(); } public class AbstractDemo01{ public static void main(String[] args){ A a = null;//声明对象 } } |
抽象类中可以声明对象。
abstract class A{ public abstract void fun(); } public class AbstractDemo01{ public static void main(String[] args){ A a = null; // 声明对象 a = new A(); // 实例化对象 } } |
对于抽象类而言,不能直接进行实例化操作。但是可以声明。
如果想使用抽象类,则必须依靠子类。抽象类必须是被子类继承的,而且子列需要是想抽象类中的全部方法。
abstract class A{ public abstract void fun(); } class B extends A{ } public class AbstractDemo02{ public static void main(String[] args){ } } |
如果B 也是抽象类,则没有必要覆写。
abstract class A{ public abstract void fun(); } abstract class B extends A{ } public class AbstractDemo02{ public static void main(String[] args){ } } |
abstract class A{ public abstract void fun(); } class B extends A{ public void fun(){ System.out.println("Hello World !!!"); } } public class AbstractDemo02{ public static void main(String[] args){ B b = new B(); b.fun(); } } |
思考:
- 抽象类能否使用final 声明。
·抽象类必须被子类继承。
·使用final声明的类不能有子类。
·所以抽象类不能使用final声明。
- 抽象类中能不能存在构造方法?。
abstract class A{ public A(){ System.out.println("AAAAAAAAAAAAAAAAAAAAAA"); // 构造方法 } public abstract void fun(); } class B extends A{ public B(){ System.out.println("BBBBBBBBBBBBBBBBBBBBBB"); // 构造方法 } public void fun(){ System.out.println("Hello World !!!"); } } public class AbstractDemo04{ public static void main(String[] args){ B b = new B(); } } |
抽象类中允许有构造方法,但此构造方法是不能直接调用的,是交给子类调用的,子类对象的实例化过程中,永远是先调用父类中的构造方法。实际上,抽象类就是比普通类多了一个抽象方法而已。
abstract class A{ private String name; public A(String name){ // 构造方法 this.name = name; } public String getName(){ return this.name; } public abstract void fun(); } class B extends A{ public B(String name){ super(name); } public void fun(){ // 覆写方法时需要注意访问权限 System.out.println(super.getName()); } } public class AbstractDemo05{ public static void main(String[] args){ B b = new B("MLDN"); b.fun(); } } |
抽象类中的属性如果要想初始化,则肯定还是依赖于构造方法。
1.2 接口(重点)
接口是一个特殊的类,在JAVA 中接口是由抽象方法和全局常量组成。在JAVA 中使用interface定义一个接口:
interface A{ private static final String INFO = "CHINA"; // 全局常量 private abstract void print(); // 抽象方法 private abstract void fun(); // 抽象方法 } |
在此接口中定义了两个抽象方法和一个全局常量。那么接口与抽象类一样,需要有子类。那么子类此时不在称为继承类,而是实现接口,通过implements 关键字完成。
interface A{ public static final String INFO = "CHINA"; // 全局常量 public abstract void print(); // 抽象方法 public abstract void fun(); // 抽象方法 } class B implements A{ // 子类 B 实现了接口 A public void print(){ // 实现抽象方法 System.out.println("Hello World !!!"); } public void fun(){ // 实现抽象方法 System.out.println(INFO); // 输出全局常量 } } public class InterfaceDemo01{ public static void main(String[] args){ B b = new B(); b.print(); b.fun(); } } |
进一步研究以上程序既然接口已经从定义上明确要求是由抽象方法和全局数据组成,那么在就扣定义的时候就可以简化操作。
interface A{ //public static final String INFO = "CHINA"; // 全局常量 String INFO = "CHINA"; // 全局常量 //public abstract void print(); // 抽象方法 void print(); // 抽象方法 //public abstract void fun(); // 抽象方法 void fun(); // 抽象方法 } class B implements A{ // 子类 B 实现了接口 A public void print(){ // 实现抽象方法 System.out.println ("Hello World!!!"); } public void fun(){ // 实现抽象方法 System.out.println(INFO); // 输出全局常量 } } public class InterfaceDemo02{ public static void main(String[] args){ B b = new B(); b.print(); b.fun(); } } |
一个类虽然只能继承一个父类,但是一个类可以实现多个接口。使用接口完成多继承的能力。
interface A{ //public static final String INFO = "CHINA"; // 全局常量 String INFO = "CHINA"; // 全局常量 //public abstract void print(); // 抽象方法 void print(); // 抽象方法 //public abstract void fun(); // 抽象方法 void fun(); // 抽象方法 } interface C{ public void fun2(); } class B implements A, C{ // 子类 B 实现了接口 A public void print(){ // 实现抽象方法 System.out.println("Hello World !!!"); } public void fun(){ // 实现抽象方法 System.out.println(INFO); // 输出全局常量 } public void fun2(){ System.out.println("信息:" + INFO); } } public class InterfaceDemo03{ public static void main(String[] args){ B b = new B(); b.print(); b.fun(); b.fun2(); } } |
如果一个子类既要实现接口又要继承抽象类则必须按照以下形式完成
Class 子类 extends 抽象类 implements 接口A,接口B{ } |
interface A{ public void printA(); } interface B{ public void printB(); } abstract class C{ public abstract void printC(); } class D extends C implements A,B{ public void printA(){ } public void printB(){ } public void printC(){ } } public class InterfaceDemo04{ public static void main(String[] args){ } } |
一个抽象类可以实现多个接口,但是一个接口不能继承多个抽象类.
interface A{ public void printA(); } interface B{ public void printB(); } abstract class C implements A,B{ public abstract void printC(); } class D extends C{ public void printA(){ } public void printB(){ } public void printC(){ } } public class InterfaceDemo05{ public static void main(String[] args){ } } |
一个接口虽然不能继承一个抽象类,但是一个接口却可以继承多个接口.这一点在日后的高级开发中会经常遇到
interface A{ public void printA(); } interface B{ public void printB(); } interface C extends A,B{ // C接口同时集成了A,B两个接口。 public void printC(); } abstract class D{ public abstract void printD(); } class X extends D implements C{ public void printA(){ System.out.println("AAAAAAAAAA"); } public void printB(){ System.out.println("BBBBBBBBBB"); } public void printC(){ System.out.println("CCCCCCCCCC"); } public void printD(){ System.out.println("DDDDDDDDDD"); } } public class InterfaceDemo06{ public static void main(String[] args){ X x = new X(); x.printA(); x.printB(); x.printC(); x.printD(); } } |
1.3 对象的多态性
接口和抽象类的基本概念完成了,下面最重要的就是对象的多态性,是整个JAVA中最重要的一个部分,因为有多态性的存在,才可以让程序变得更加灵活。
多态性是面向对象的最后一个特征:
·方法的重载和方法的覆写实际上就属于多药性的一种体现;
·真正地多态性中还包含一种称为对象多态性的概念。
·对象多态性主要指的是,子类和父类对象的相互转换关系。
·向上转型: 父类 父类对象 = 子类实例 à 自动完成
·向下转型:子类 子类对象 = (子类)父类实例 à 强制完成
说明:下面讲解的程序只是让对象多态性的概念得到体现,当然其本身不包含任何具体意义。
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } public class PolDemo01{ public static void main(String[] args){ B b = new B(); b.fun2(); } } |
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } public class PolDemo01{ public static void main(String[] args){ A a = new B(); // 发生向上转型,子类实例 --> 父类实例 a.fun2(); } } |
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } public class PolDemo01{ public static void main(String[] args){ A a = new B(); // 发生向上转型,子类实例 --> 父类实例 a.fun2(); a.fun3(); } } |
如果此时想要使用fun3(),那么应该发生向下的转型关系。
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } public class PolDemo02{ public static void main(String[] args){ A a = new B(); // 发生向上转型,子类实例 --> 父类实例 B b = (B) a; // 发生向下转型, 强制。 b.fun3(); b.fun2(); } } |
明白了以后,再来看以下的程序:
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } public class PolDemo03{ public static void main(String[] args){ A a = new A(); B b = (B) a; b.fun2(); } } |
Exception in thread "main" java.lang.ClassCastException: A cannot be cast to B at PolDemo03.main(PolDemo03.java:24) |
此一场是继NullPointerException(空指向异常)之后,第二个最经常出现的异常,表示类转换异常.造成的根本原因是两个没有关系的类进行相互的对象转换操作。
观察对象多态性的应用:
·例如:现在要设计一个方法,那么次方法可以接受A类的所有子类的实例。
如果现在不使用对象的多态性概念来完成,则代码如下:
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } class C extends A{ public void fun1(){ // 方法被覆写了 System.out.println("4. C 类 --> public void fun1(){}"); } public void fun4(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("5. C 类 --> public void fun4(){}"); } } public class PolDemo04{ public static void main(String[] args){ fun(new B()); fun(new C()); } public static void fun(B b){ b.fun2(); b.fun3(); } public static void fun(C c){ c.fun2(); c.fun4(); } } |
以上方法是通过重载完成,么使用以上方法完成会存在以下缺点:
如果现在A的子类有10000000个,那么此方法就要重载10000000次,而且在每次增加子类的时候都需要修改代码本身,所以使用对象的多态性就可以很好的解决此类问题,因为所有的对象都会发生自动的向上转型:
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } class C extends A{ public void fun1(){ // 方法被覆写了 System.out.println("4. C 类 --> public void fun1(){}"); } public void fun4(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("5. C 类 --> public void fun4(){}"); } } public class PolDemo05{ public static void main(String[] args){ fun(new B()); fun(new C()); } public static void fun(A a){ a.fun2(); } } |
但是以上的操作也会尊在一个小的问题:
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } class C extends A{ public void fun1(){ // 方法被覆写了 System.out.println("4. C 类 --> public void fun1(){}"); } public void fun4(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("5. C 类 --> public void fun4(){}"); } } public class PolDemo06{ public static void main(String[] args){ fun(new B()); fun(new C()); } public static void fun(A a){ a.fun2(); B b = (B) a; b.fun3(); } } |
以上仍然会出现类型转换异常,那么现在希望,如果传入的是B类的实例免责调用fun3(),如果是C类则调用fun4();那么想要完成这样的功能就需要判断传进的对象到底是哪个类的实例了。
在java 中提供了instanceof关键字完成这样的功能
对象 instanceof 类 à 返回boolean类型的数据,返回值就是true或false。 |
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); } public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } class C extends A{ public void fun1(){ // 方法被覆写了 System.out.println("4. C 类 --> public void fun1(){}"); } public void fun4(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("5. C 类 --> public void fun4(){}"); } } public class PolDemo07{ public static void main(String[] args){ A a = new B(); System.out.println(a instanceof A); System.out.println(a instanceof B); System.out.println(a instanceof C); } } |
class A{ public void fun1(){ System.out.println("1. A 类 --> public void fun1(){}"); } public void fun2(){ this.fun1(); } } class B extends A{ public void fun1(){ // 方法被覆写了 System.out.println("2. B 类 --> public void fun1(){}"); }
public void fun3(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("3. B 类 --> public void fun3(){}"); } } class C extends A{ public void fun1(){ // 方法被覆写了 System.out.println("4. C 类 --> public void fun1(){}"); } public void fun4(){ // 此操作为子类自己定义的,父类中不存在。 System.out.println("5. C 类 --> public void fun4(){}"); } } public class PolDemo08{ public static void main(String[] args){ fun(new B()); fun(new C()); } public static void fun(A a){ a.fun2(); if(a instanceof B){ B b = (B) a; b.fun3(); } if(a instanceof C){ C c = (C) a; c.fun4(); } } } |
明白之后,得出一个结论:
·为了保证对象的向下转型操作正确,在操作前最好加上instanceof 关键字进行判断。
·在继承关系中,父类的设计很重要,只要父类设计合理了,则代码开发就非常简便。
1.4 抽象类的实际应用(模板设计)
从对象多态性的概念上来看,子类为父类实例化是一个比较容易的操作,因为可以发生自动的向上转型关系,那么调用的方法永远是被子类覆写过的方法。
那么,此时就可以利用概念通过对象多态性为抽象类实例化。
abstract class A{ public abstract void fun(); } class B extends A{ public void fun(){ System.out.println("Hello World !!!"); } } public class AbstPolDemo01{ public static void main(String[] args){ A a = new B(); a.fun(); } } |
此时已经完成了抽象类的实例化操作。
例如:人分为两种,分为老师和学生,假设老师和学生都有姓名和年龄属性。但是老师有工资,学生有成绩。老师和学生都可以说话,但是说话的内容不一样。说话应该是一个具体的功能,但是说话的内容应该由各个子类单独实现。
abstract class Person{ private String name; private int age; public Person(String name, int age){ this.name = name; this.age = age; } public String getName(){ return this.name; } public int getAge(){ return this.age; } public void Say(){ System.out.println(this.getContent()); } public abstract String getContent(); }
class Student extends Person{ private double score; public Student(String name, int age, double score){ super(name, age); this.score = score; } public double getScore(){ return this.score; } public String getContent(){ return "学生说:\n\t姓名:" + super.getName() + "\n\t年龄:" + super.getAge() + "\n\t成绩:" + this.getScore(); } }
class Teacher extends Person{ private double salary; public Teacher(String name, int age, double salary){ super(name, age); this.salary = salary; } public double getSalary(){ return this.salary; } public String getContent(){ return "老师说:\n\t姓名:" + super.getName() + "\n\t年龄:" + super.getAge() + "\n\t工资:" + this.getSalary (); } } public class AbstPolDemo02{ public static void main(String[] args){ Person per1 = new Student("张三", 20, 99); Person per2 = new Teacher("李四", 20, 9900); per1.Say(); per2.Say(); } } |
违纪卡 |
|||
姓名 |
|
班级 |
|
日期 |
|
原因 |
|
此种设计思路在程序中称为模板设计,所以抽象类本身最大的用处就在于模板设计。
1.5 接口的实际应用
接口也可以像抽象类那样通过对象多态性进行对象的实例化操作。
interface A{ public void fun(); } class B implements A{ public void fun(){ System.out.println("Hello World !!!"); } }
public class InterPolDemo01{ public static void main(String[] args){ A a = new B(); // 为接口实例化 a.fun(); } } |
抽象类可以用于定义模板,但是接口呢?
接口实际上是作为一种标准存在的。例如,电脑实现了USB接口,U盘,打印机等设备也都实现了USB接口。
interface USB{ public void Start(); public void Stop(); } class Computer{ public static void plugin(USB usb){ usb.Start(); usb.Stop(); } } class Flash implements USB{ public void Start(){ System.out.println("U盘开始工作"); } public void Stop(){ System.out.println("U盘停止工作"); } } class Print implements USB{ public void Start(){ System.out.println("打印机开始工作"); } public void Stop(){ System.out.println("打印机停止工作"); } } public class InterPolDemo02{ public static void main(String[] args){ Computer.plugin(new Flash()); Computer.plugin(new Print()); } } |
1.6 设计模式(接口和抽象类的应用)
1.6.1 适配器设计模式
正常情况下一个接口的子类要实现全部的抽象方法.
interface Window{ public void open(); public void close(); public void icon(); public void unicon(); } class MyWindow implements Window{ } public class AdpaderDemo01{ public static void main(String[] args){ } } |
在MyWindow类中,此时肯定要覆写全部的抽象方法,但是现在希望可以根据自己的需要来选择性的覆写,那么,有还怎办呢?
应该用一个类先将接口实现了,但是所有的方法都属于空实现,之后再继承此类。
应该使用抽象类,应为抽象类也不能直接使用。
interface Window{ public void open(); public void close(); public void icon(); public void unicon(); } abstract class WindowAdpater implements Window{ public void open(){} public void close(){} public void icon(){} public void unicon(){} } class MyWindow extends WindowAdpater{ public void open(){ System.out.println("打开窗口 !"); } } public class AdpaterDemo01{ public static void main(String[] args){ Window win = new MyWindow(); win.open(); } } |
1.6.2 工厂设计模式
现在有如下一道程序
interface Fruit{ public void ate(); }
class Apple implements Fruit{ public void ate(){ System.out.println("An apple was ate ..."); } } class Orange implements Fruit{ public void ate(){ System.out.println("An orange was ate ..."); } } public class InterDemo01{ public static void main(String[] args){ Fruit fruit = new Apple(); fruit.ate(); } } |
以上的程序如果开发的话是否存在问题???
一直在强调:主方法其实就是一个客户端,客户端的代码越简单越好。
interface Fruit{ public void ate(); } class Apple implements Fruit{ public void ate(){ System.out.println("An apple was ate ..."); } } class Orange implements Fruit{ public void ate(){ System.out.println("An orange was ate ..."); } } class Factory{ // 工厂类 public static Fruit getFruit(String className){ Fruit fruit = null; if("apple".equals(className)){ fruit = new Apple(); } if("orange".equals(className)){ fruit = new Orange(); } return fruit; } } public class InterDemo01{ public static void main(String[] args){ Fruit fruit = Factory.getFruit(args[0]); if(fruit != null){ fruit.ate(); } } } |
Factory类设计 |
if("apple".equals(className)){ fruit = new Apple(); } |
使用"apple".equals(className)判断而不是className.equals("apple"),是为了避免NullPointerException(空指向异常),其实这也是一种有效避免NullPointerException异常的有效方式。 |
所有的实例化对象都是从工厂类取得的,那么客户端调用的时候,根据传入的名称不同,完成的功能也不同。
1.6.3 代理设计模式
现在有如下一种情况,生活中的情况:
张某属于老好人,也特别有银子,之后马某向张某借了10000000这么多钱。规定一年后还清,但是一年之后,当张某向马某讨债的时候。张某无奈之下找到了范某,范某经营一家讨债公司。范某为了成功把钱讨回来,准备了小刀、绳索、钢筋、钢据、手-枪、毒-品……然后马某就害怕了,还清了钱。然后范某销毁所有罪证。
·张某à范某à讨债 ·范某只是一个代理公司,核心还是张某向马某讨债。
interface Give{ public void giveMoney() ; } class RealGive implements Give{ public void giveMoney(){ System.out.println("把钱还给我。。。。。") ; } } class ProxyGive implements Give{ // 代理公司 private Give give = null ; public ProxyGive(Give give){ this.give = give ; } public void giveMoney(){ this.before() ; this.give.giveMoney() ; // 代表真正的讨债者完成讨债的操作 this.after() ; } public void before(){ System.out.println("准备:小刀、绳索、钢筋、钢据、手-枪、毒-品") ; } public void after(){ System.out.println("销毁所有罪证") ; } } public class ProxyDemo{ public static void main(String args[]){ Give give = new ProxyGive(new RealGive()) ; give.giveMoney() ; } } |
1.6.4 接口和抽象类的区别
抽象类和接口如此的相似,那么在使用的时候到底用该选在哪一个呢????
No. |
比较点 |
抽象类 |
接口 |
|
组成 |
抽象方法、普通方法、常量、变量、构造方法、全局常量 |
抽象方法、全局常量 |
|
定义 |
abstract |
interface |
|
子类 |
子类通过extends继承抽象类 |
子类通过implements实现接口 |
|
限制 |
一个子类只能继承一个抽象类 |
一个子类可以实现多个接口 |
|
关系 |
一个抽象类可以实现多个接口 |
一个接口不能继承一个抽象类只能实现多个接口 |
一个抽象类中可以包含多个接口 |
一个接口中可以包含多个抽象类 |
||
|
设计模式 |
模板设计 |
工厂设计、代理设计 |
两个一起使用可以完成适配器设计 |
|||
|
实例化 |
都是通过对象的多态性,通过子类进行对象的实例化操作 |
从以上表格发现,如果抽象类和接口都可以使用的话,那么优先使用接口,因为接口可以避免单继承的局限。
1.7 匿名内部类
内部类:在一个类的内部还有另一个类,称为内部类,匿名内部类是在抽象类和接口的基础上发展起来的。只要有抽象方法才可能形成匿名内部类。
interface A{ public void fun() ; } class B implements A{ public void fun(){ System.out.println("Hello World!!!") ; } } class X{ public void fun1(A a){ a.fun() ; } public void fun2(){ this.fun1(new B()) ; } } public class NonameDemo01{ public static void main(String args[]){ new X().fun2() ; } } |
思考:如果现在B类只使用了一次,那么还有必要将其定义成一个单独的类。那么此时就可以使用匿名内部类了
interface A{ public void fun() ; } class X{ public void fun1(A a){ a.fun() ; } public void fun2(){ this.fun1(new A(){ public void fun(){ System.out.println("Hello World!!!") ; } }) ; } } public class NonameDemo02{ public static void main(String args[]){ new X().fun2() ; } } |
在一般开发中匿名你不累使用较少,现在只有两种情况下可以经常看见匿名内部类的使用:
·Java的图形界面
·Spring 开发框架
1.8 包装类
在Java中提倡一种概念:一切皆对象。但是这样一来就会出现一个矛盾点,数据类型分为基本数据类型和引用数据类型,基本数据类型是类吗???
为例解决这样的矛盾,在Java中针对八种基本数据类型,设置了八种包装类,用于以类的形式表示基本数据类型。
No. |
基本数据类型 |
包装类 |
1. |
int |
Integer |
2. |
char |
Character |
3. |
float |
Float |
4. |
double |
Double |
5. |
byte |
Byte |
6. |
short |
Short |
7. |
long |
Long |
8. |
boolean |
Boolean |
这八种包装类实际上可以分为两组:
·数值型:Integer、Float、Double、Byte、Short、Long
·其他类型:Character、Boolean
方法摘要 |
|
|
byteValue |
|
doubleValue |
|
floatValue |
|
intValue |
|
longValue |
|
shortValue |
以上的方法的返回值都是基本数据类型
正常情况下降一个int变为Integer属于使用类的形式表示证书,但是int本身表示剧本的数字,基本的数字可以进行+、-、*、/的操作。
在包装类的操作中存在装箱及拆箱的操作:
·装箱操作:将基本数据类型变为包装类称为装箱操作
·拆箱操作:将包装类变为基本数据类型称为拆箱操作
下面以Integer和Float为例,来观察装箱和拆箱的操作。
public class IntegerDemo01{ public static void main(String args[]){ int i = 10 ; Integer i2 = new Integer(i) ; // 装箱操作 int j = i2.intValue() ; // 拆箱操作 System.out.println(j * j) ; } }; |
如果现在使用的是Float呢???
public class FloatDemo01{ public static void main(String args[]){ float i = 10.3f ; Float i2 = new Float(i) ; // 装箱操作 float j = i2.floatValue() ; // 拆箱操作 System.out.println(j * j) ; } }; |
以上的做法是在JDK 1.5之前的,在JDK1.5之前所有的数据必须进行手工的装箱操作,而且包装类本身不能进行任何的数学运算,例如:包装类对象++。
但是在JDK 1.5之后增加了很多的新特性,例如:foreach、可变参数。自动装箱及拆箱操作
public class IntegerDemo02{ public static void main(String args[]){ int i = 10 ; Integer i2 = i ; // 自动装箱操作 int j = i2 ; // 自动拆箱操作 System.out.println(j * j) ; } }; |
对于Float也是一样
public class FloatDemo02{ public static void main(String args[]){ float i = 10.3f ; Float i2 = i ; // 装箱操作 float j = i2 ; // 拆箱操作 System.out.println(j * j) ; } }; |
实际上通过包装类也可以去的最大值和最小值
public class IntegerDemo03{ public static void main(String args[]){ System.out.println(Integer.MAX_VALUE) ; System.out.println(Integer.MIN_VALUE) ; } }; |
对于包装类来讲,自动装箱和拆箱功能是一个重要的特点,但是最重要的特点还有一个:
·可以将字符串转换为基本数据类型
范例:将字符串转换为int型
·方法:
public static int parseInt(String s) throws NumberFormatException |
操作:
public class IntegerDemo04{ public static void main(String args[]){ String str = "121233" ; // 字符串由数字组成 int i = Integer.parseInt(str) ; // 将字符串变为int型 System.out.println(i++) ; } }; |
但是需要注意的是,字符串必须由数字组成,如果有非数字存在,则会出现代码错误:
public class IntegerDemo04{ public static void main(String args[]){ String str = "12sss3" ; // 字符串由数字组成 int i = Integer.parseInt(str) ; // 将字符串变为int型 System.out.println(i++) ; } }; |
既然可以将字符串转换为int型数据,那么就可以将字符串转换为float型数据
public class FloatDemo03{ public static void main(String args[]){ String str = "12.3" ; // 字符串由数字组成 float i = Float.parseFloat(str) ; // 将字符串变为int型 System.out.println(i*i) ; } }; |
1.9 Object类
在Java中一切都是继承关系。
class Person{ } |
那么既然一切都是继承关系,如果一个类没有明确继承那个父类,子默认情况下及时继承Object类实际上以上语法应该写成以下像是。
class Person extends Object{ } |
那么证明任何类都可以用Object进行接收。
public class ObjectDemo02{ public static void main(String[] args){ Object obj1 = new Person(); Object obj2 = "Hello World !!!"; } } |
那么,多余Object接收来讲,不仅可以接收类的引用,只要是引用数据类型都可以使用Object类使用
interface National{ } class Person extends Object implements National{ } public class ObjectDemo03{ public static void main(String[] args){ National na = new Person(); // 子类为借口实例化 Object obj = na; // 使用Object接收接口实例。 National temp = (National) obj; } } |
观察使用Object接收数组类型的数据:
public class ObjectDemo04{ public static void main(String arg[]){ int i[] = {1,2,3,4,5,6,7,8} ; // 数组 Object obj = i ; // 使用Object接收数组 int x[] = (int[]) obj ; // 向下转型 for(int j=0;j<x.length;j++){ System.out.print(x[j] + "、") ; } System.out.println(); } }; |
Object类的主要功能不仅于此,对于一个完整的类来讲,应该覆写Object类中的以下三个方法:
·toString():对象打印室调用,public String toString()
·equals():对象比较式调用,实际上String类就已经覆写好了此方法, public boolean equals(Object obj)
·hashCode():暂时不了解,public int hashCode()
先来看toString方法
class Person{ public String toString(){ // 覆写了toString()方法 return "Hello" ; } }; public class ObjectDemo05{ public static void main(String arg[]){ System.out.println(new Person()) ; } }; |
发现此时直接输出对象时,实际上就是调用了toString()方法,那么因为此方法已经被子类覆写过了,所以最终被调用的就是被覆写过的方法。
也就是说toString()是表示对象信息的。
class Person{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public String toString(){ // 覆写了toString()方法 return "姓名:" + this.name + ",年龄:" + this.age ; } }; public class ObjectDemo06{ public static void main(String arg[]){ System.out.println(new Person("张三",30)) ; } }; |
在Object类中标准的对象比较方法就是equals方法。那么如果要进行对象比较,在系统中找的也是equals方法。
class Person{ private String name ; private int age ; public boolean equals(Object obj){ // 是完成对象的比较操作 if(this==obj){ // 两个地址相等 return true ; } if(!(obj instanceof Person)){ // 不是同一个类型 return false ; } Person per = (Person)obj ; if(this.name.equals(per.name)&&this.age==per.age){ return true ; }else{ return false ; } } public Person(String name,int age){ this.name = name ; this.age = age ; } public String toString(){ // 覆写了toString()方法 return "姓名:" + this.name + ",年龄:" + this.age ; } }; public class ObjectDemo07{ public static void main(String arg[]){ System.out.println(new Person("张三",30).equals("hello")) ; } }; |
public class ObjectDemo07{ public static void main(String arg[]){ System.out.println(new Person("张三",30).equals(new Person("张三",30))) ; } }; |
Object类可以接受任意类型的对象引用.
1.10 练习题
现在有如下代码,请说出正确答案。
abstract class A{ public A(){ this.print() ; } public abstract void print() ; } class B extends A{ private int x = 100 ; public B(int x){ this.x = x ; } public void print(){ System.out.println("x = " + x) ; } } public class TestJava{ public static void main(String args[]){ A a = new B(10) ; } } |
子类对象的实例化过程:先去调用父类中的构造方法,之后再执行子类自己的构造方法,父类的构造方法执行完之后,知己上就是为父类中的属性初始化了,但是为执行完的话,子类的构造方法就永远不可能调用,那么,子类中的所有属性都无法初始化,无法初始化,那么默认值就是 0.