第5章 Java高级特性
5.1 封装性
封装是指将类中的某些信息隐藏在类的内部,不允许外部程序直接访问,只能通过 该类提供的方法实现对隐藏信息的访问或操作。
e.g.
class Student{private String name;private int age;// 带参数构造方法Student(String name,int age){this.name = name;this.age = age;}// 获取name的信息String getName(){return name;}// 设置age的值void setAge(int age){this.age = age;}// 获取age信息int getAge(){return age;}
}public class Demo1 {public static void main(String[] args) {// 创建Student的实例(对象) s1Student s1 = new Student("张三",18);// 修改age字段的值s1.setAge(19);System.out.printf("姓名:%s,年龄:%d",s1.getName(),s1.getAge());}
}
5.2 继承
继承是指子类可以拥有父类的全部属性和行为(方法),是类与类之间的一种关系。Java中类的继承只支持单继承,即一个子类只能继承一个父类。
e.g.
// 定义基类
class People{private String name;private int age;// 父类的构造方法People(String name,int age){this.name = name;this.age = age;}void show(){System.out.printf("姓名:%s,年龄:%d\n",name,age);}// 获取name信息String getName(){return name;}// 修改字段age的值void setAge(int age){this.age = age;}// 获取age信息int getAge(){return age;}
}// 定义子类
class Student extends People{// 子类中构造方法Student(String name,int age){// 调用父类的构造器完成对象的初始化操作super(name,age);}// 重写父类中的show()方法,从而实现对父类方法的修改或覆盖@Overridevoid show() {// 调用父类中的show()方法super.show();System.out.println("这是子类中的show()方法");}
}public class Demo1 {public static void main(String[] args) {// 创建Student的实例(对象) s1Student s1 = new Student("李四",18);s1.setAge(19);s1.show();}
}
5.3 方法的重载和重写
1、方法的重载(同一个类中)
方法名相同,方法的参数列表不同。
PS: 与方法的返回类型无关,返回类型可以相同也可以不同。
e.g.
public class Demo2 {// 返回两个数的最大值static double max(int x,float y){return x>y?x:y;}//返回三个数的最大值,与上面的方法构成重载static double max(int x,float y,double z){return x>y?(x>z?x:z):(y>z?y:z);}//返回三个数的最大值,与上面的方法构成重载static double max(float x,int y,double z){return x>y?(x>z?x:z):(y>z?y:z);}public static void main(String[] args) {System.out.println(max(2,.5f));System.out.println(max(23,.5f,3.14));System.out.println(max(2f,5,3.14));}
}
2、方法的重写(在不同的类中)
指在子类中重写父类中的方法,从而实现对父类方法的修改或覆盖;
PS: 重写时,不能使用比父类方法更严格的访问权限修饰符。
e.g.
// 父类
class Animal{void run(){System.out.println("动物在奔跑");}
}// 子类
class Cat extends Animal{// 重写父类中的run()方法,void run(){System.out.println("猫在抓老鼠");}
}public class Demo3 {public static void main(String[] args) {Cat c1 = new Cat();c1.run();}
}
5.4 对象的类型转换
(1)向上转型
父类的引用指向子类的对象;
(2)向下转型
子类的引用指向父类的对象;
e.g.
// 基类
class Person{void run(){System.out.println("在跑步");}
}// 子类
class Student extends Person{@Overridevoid run() {System.out.println("学生在跑步");}// 子类中定义的方法void study(){System.out.println("学生在学习");}
}public class Demo1 {public static void main(String[] args) {// 向上转型:父类的引用指向子类的对象Person p1 = new Student();p1.run();// p1.study(); 不能调用子类中定义的成员// 向下转型:子类的引用指向父类的对象Student s1 = (Student) p1;s1.run();s1.study();}
}
关于对象类型转换的两点说明:
(1)向上转型对象只能访问从基类继承的成员及重写的方法,子类中定义的成员不能被访问;
(2)向上转型可以减少重复代码,提高系统的扩展性;
5.5 多态性
多态指同一种行为(方法)具有多种表现形态;
(1)编译时多态(静态的)
主要指方法的重载,编译时通过方法参数列表不同来进行区分;
(2)运行时多态(动态的)
同一类型的引用使用不同的实例而执行不同的操作,产生不同的结果; 实现方式:继承、接口
class Animal{void run(){System.out.println("动物在奔跑");}
}class Cat extends Animal{void run(){System.out.println("猫在抓老鼠");}
}class Dog extends Animal{void run(){System.out.println("狗在奔跑");}
}public class Demo2 {void show(Animal a){a.run();}public static void main(String[] args) {Animal a = new Animal();// 向上转型Animal a1 = new Cat();Animal a2 = new Dog();Demo2 d2 = new Demo2();// 多态的表现d2.show(a);d2.show(a1);d2.show(a2);}
}
5.6 可变长参数
e.g.
public class Demo3 {int f(int x,int y){System.out.println("+++++++++");return x+y;}int f(int x,int y,int z){return x+y+z;}
// // 与第1、2个方法构成重载
// int f(int[] x){
// int sum=0;
// for(int k:x){
// sum+=k; // sum=sum+k;
// }
// return sum;
// }// 与第1、2个方法构成重载;与第3个方法不构成重载,系统认为这两个方法等价int f(int ... x){int sum=0;for(int k:x){sum+=k; // sum=sum+k;}return sum;}public static void main(String[] args) {Demo3 d3 = new Demo3();System.out.println(d3.f(new int[]{25,30,40,50,60}));System.out.println(d3.f(20,30));}
}
public class Demo4 {static void f(String ... str){String s1 = "";for(String s : str){s1 +=s;}System.out.println(s1);}public static void main(String[] args) {f("Hello"," ","Java","!");}
}
5.7 抽象类
使用abstract修饰的类称为抽象类;
e.g.
// 抽象类
abstract class A{// 抽象方法abstract double area(int r);
}class B extends A{// 实现抽象类中的抽象方法double area(int r){return Math.PI*r*r;}
}public class Demo3 {public static void main(String[] args) {B b = new B();System.out.println(b.area(5));System.out.println(b.area(10));}
}
e.g.
// 抽象类
abstract class A{int r;int w,h;// 构造器A(int r){this.r = r;}A(int w,int h){this.w = w;this.h = h;}// 抽象方法abstract double area();
}class B extends A{B(int r){super(r);}// 实现抽象类中的抽象方法double area(){return Math.PI*r*r;}
}class C extends A{C(int w,int h){super(w,h);}// 实现抽象类中的抽象方法double area(){return w*h;}
}public class Demo3 {public static void main(String[] args) {B b = new B(3);System.out.println(b.area());C c = new C(4,5);System.out.println(c.area());}
}
关于抽象类的几点说明:
A、由于抽象类是需要继承的,所有不能使用final修饰;
B、抽象类的子类也可是抽象类;
C、抽象类不能使用new来实例化,但可以有构造器;
D、抽象方法必须存在于抽象类中,且不能使用static、final修饰;
E、子类实现抽象类时,必须实现抽象类中的所有抽象方法;
5.8 接口
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”即接口。
接口中的成员包含:全局常量、公共抽象方法、静态方法。
e.g.
public interface Itf1 {// var: 默认是 public static final的double PI=3.1415926;// abstract method: 默认是 public abstract的double area(int r);// static method: 默认是 public 的static void f(){System.out.println("这是接口中的静态方法");}
}
// 实现接口 Itf1
public class Demo7 implements Itf1{// 实现接口中的抽象方法public double area(int r) {return PI*r*r;}public static void main(String[] args) {// 创建类的实例(对象)Demo7 d7 = new Demo7();double s = d7.area(5);System.out.println("圆的面积为:"+s);// 调用接口中的静态方法Itf1.f();}
}
关于接口的几点说明:
①接口中的变量会隐式指定为public static final的,即全局常量;
②接口中的抽象方法会隐式指定为public abstract的;
③接口中不能定义代码块、构造器;
④接口中可以定义静态方法(默认是public的),但不能被继承;
⑤接口支持多继承;类只支持单继承;
⑥一个类可以实现多个接口。
e.g.
public interface Itf2{double E = 2.71828;
}// 接口的多继承
public interface Itf3 extends Itf1,Itf2{}// 一个类可以实现多个接口,实现接口 Itf1,Itf2,Itf3
public class Demo7 implements Itf1,Itf2,Itf3 {// 实现接口中的抽象方法public double area(int r) {return PI*r*r;}public static void main(String[] args) {// 创建类的实例(对象)Demo7 d7 = new Demo7();double s = d7.area(5);System.out.println("圆的面积为:"+s);}
}
*5.9 枚举
枚举是一种特殊的类,一般表示一组常量;
e.g.
public enum Season {Spring,Summer,Autumn,Winter;
}
public class Demo8 {public static void main(String[] args) {Season s1 = Season.Spring;System.out.println(s1);System.out.println(Season.Winter.ordinal());for (Season k : Season.values()){System.out.println(k);}}
}
interface BH{void show();
}
public enum Color implements BH{RED("红色",0),BLACK("黑色",1);String name;int index;Color(String name,int index){this.name = name;this.index = index;}public void show(){System.out.println(index+":"+name);}public static void main(String[] args) {Color c1 = Color.BLACK;System.out.println(c1.index);System.out.println(c1.name);c1.show();}
}
关于枚举的几点说明:
①枚举是一种特殊的类;
②枚举中可以定义属性、构造器、代码块、方法;
*5.10设计模式
设计模式是指在大量的实践中总结和理论化之后优选的代码结构、编程风格、及解决问题的思考方法,如同经典的棋谱。
1、单例设计模式
采取一定的方法保证在整个软件系统中,对某个类只能存在一个实例,
并且该类提供一个取得其实例的方法。
e.g.
class Singleton{private Singleton(){System.out.println("Hello Singleton!");}// 饿汉式模式private static Singleton st = new Singleton();public static Singleton getInstance(){return st;}
// // 懒汉式模式
// private static Singleton st = null;
// public static Singleton getInstance(){
// if(st==null){
// st = new Singleton();
// }
// return st;
// }
}
public class Singleton_test {public static void main(String[] args) {Singleton st1 = Singleton.getInstance();Singleton st2 = Singleton.getInstance();System.out.println(st1==st2);}
}
2、工厂模式
定义一个用于创建对象的接口,让子类去决定实例化哪一个类。 工厂模式使一个类的实例化延迟到其子类。
e.g.
interface IWork{void doWork();
}
class StudentWork implements IWork{public void doWork(){System.out.println("XM is doing homework.");}
}
class TeacherWork implements IWork{public void doWork(){System.out.println("The teacher is correcting hemowork.");}
}interface IWorkFactory{IWork getWork();
}
class StudentWorkFactory implements IWorkFactory{public IWork getWork(){return new StudentWork();}
}
class TeacherWorkFactory implements IWorkFactory{public IWork getWork(){return new TeacherWork();}
}// 主类
public class FactoryTest {public static void main(String[] args) {IWorkFactory i1 = new StudentWorkFactory();i1.getWork().doWork();IWorkFactory i2 = new TeacherWorkFactory();i2.getWork().doWork();}
}
3、代理模式
为其对象提供一种代理以控制对这个对象的访问。
e.g.
interface Iobject{void action();
}
class A implements Iobject{public void action() {System.out.println("...被代理类开始执行...");}
}
class ProxyObject implements Iobject{Iobject obj;ProxyObject(){System.out.println("=====ProxyObject=====");obj = new A();}public void action() {System.out.println("++++代理类开始执行++++");obj.action();}
}
public class ProxyTest {public static void main(String[] args) {Iobject iobj = new ProxyObject();iobj.action();}
}