Java复用类
类复用的方式有两种
一:组合语法
组合语法:当我们新建一个类时,类里的一些数据成员由现有的类组成、也包括基本数据类型。
package com.JavaSE02.demo06;
//把一个类,放到另外一个类里去使用,这种方式称之为组合
public class SprinklerSystem {
private String value1,value2,value3;
private WaterSource source=new WaterSource();//这就是组合语法
private int i;
private float f;
public String toString(){
//source 返回的是一个字符串;因为我们在WaterSource里重写了toString方法,而这里要求返回的是String,所以返回的时候回调用WaterSource的toString
return "value1="+value1+" value2="+value2+" value3"+value3+" i="+i+" f="+f+" source="+source;
}
public static void main(String[] args) {
SprinklerSystem sprinklerSystem = new SprinklerSystem();
System.out.println(sprinklerSystem.toString());
}
}
class WaterSource{
private String s;
WaterSource(){
System.out.println("WaterSource()");
s="Construcoted";
}
public String toString(){
return s;
}
}
在组合语法中变量初始化有四种不同的方式:
1.在声明的地方赋值 如: Myclass myclass= new Myclass();
2.构造器
3.在使用对象之前,检查其是否null,为null才对此初始化(称为惰性初始化)
4.使用实例初始化,在方法外面,类的里面使用一对大括号进行实例初始化
以下是实验代码
package com.JavaSE02.demo06;
public class Bath {
private String s1 ="Happy",s2="Happy"//这是第一种初始化方式,在声明的地方进行赋值
,s3,s4;
private Soap castille;
private int i;
private float toy;
public Bath(){//这是第二种初始化方式:在构造器里进行初始化。
System.out.println("Inside Bath()");
s3="Joy";
toy=3.14f;
castille=new Soap();
}
{ i = 47;}//这是第三种初始化方式:实例初始化
public String toString(){//这是第四种初始化方式:延迟初始化(惰性初始化):用的时候先检查;好处节省内存资源
if(s4==null){
s4="Joy";
}
return "s1="+s1+"\n"+
"s2="+s2+"\n"+
"s3="+s3+"\n"+
"s4="+s4+"\n"+
"i="+i+"\n"+
"toy="+toy+"\n"+
"castille="+castille+"\n";
}
public static void main(String[] args) {
Bath bath = new Bath();
System.out.println(bath.toString());
}
}
class Soap{
private String s;
Soap(){
System.out.println("Soap()");
s="Constructed";//第二种初始化方式;在构造器里面赋值
}
public String toString(){
return s;
}
}
二:继承语法 extends关键字
继承语法 extends
按照先有类的类型来创建新类
package com.JavaSE02.demo06;
public class Detergent extends Cleaner {
//代码复用:把属于基本通用的模块所拥有的功能或数据成员集中写到基类当中,这样基类中的代码就没有必要在子类中再写一次;在子类直接super调用即可。
@Override
public void scrub(){
append("Detergent.scrub()");
super.scrub();
}
public void foam(){
append(" foam() ");
}
public static void main(String[] args) {
Detergent detergent = new Detergent();
detergent.scrub();
detergent.dilute();
detergent.apply();
detergent.foam();
System.out.println(detergent);
System.out.println("测试基类");
Cleaner.main(args);
}
}
class Cleaner{
private String s="Cleanser ";
public void append(String s){
this.s+=s;
}
public void dilute(){
append(" dilute()");
}
public void apply(){append(" apply()");}
public void scrub(){append(" scrub()");}
public String toString(){return s;}
public static void main(String[] args){
Cleaner cleaner = new Cleaner();
cleaner.dilute();
cleaner.apply();
cleaner.scrub();
System.out.println(cleaner);
}
}
//以下是代码运行结果
/**
Cleanser Detergent.scrub() scrub() dilute() apply() foam()
测试基类
Cleanser dilute() apply() scrub()
*/
初始化基类
Question.当我们new一个子类的时候,调不调用父类的constructor?调用的话什么时候被调用?
Answer.当我们new一个对象时,如果这个对象有父类,那么这个父类的构造器会被调用;
package com.JavaSE02.demo06;
//结果是首先是执行最顶层基类的consructor,然后逐层降低依次执行constructor直到现在使用的类;
//当我们new一个对象时,如果这个对象有父类,那么这个父类的构造器会被调用;
public class Cartoon extends Drawing {
public Cartoon(){
System.out.println(" Cartoon() ");
}
public static void main(String [] args){
Cartoon x = new Cartoon();
}
}
class Drawing extends Art{
public Drawing(){
System.out.println(" Drawing Constructor ");
}
}
class Art{
public Art(){
System.out.println(" Art Consrtuctor ");
}
}
//以下是输出结果
/**
Art Consrtuctor
Drawing Constructor
Cartoon()
*/
复用类中的代理
代理:一种相似于代理的模式,并不是真正的代理模式
代理方式:实现了继承的功能,但实际上用的是组合;
在组合与继承之间选择
组合属于显式的在类中存放对象,需要new;而继承是隐式的,使用exntends关键字即可;
那么这两种方式分别在什么场景下应用?
组合一般是用在想在新类中使用现有类的功能,而并不是使用现有类的接口;
以SpaceShip(飞船)和SpaceShipControle(飞船控制器)为例
package com.JavaSE02.demo07;
//这是飞船控制器
public class SpaceShipControle {
void up(int velocity){}
void down(int velocity){}
void left(int velocity){}
void right(int velocity){}
void forward(int velocity){}
void back(int velocity){}
void turboBoost(){}
}
//这是另外一个类,飞船代理器,可以实现所有控制器的功能,但又不是直接访问控制器;目的是便于理解
package com.JavaSE02.demo07;
//这就是代理模式,实现了继承的功能,但实际上用的是组合;
public class SpaceShipDelegation {
private String name;
private SpaceShipControle controle=new SpaceShipControle();//组合语法
public SpaceShipDelegation(String name){
this.name=name;
}
//以组合的方式,把所有公开的接口都暴露在外
public void up(int velocity){
controle.up(velocity);
}
public void down(int velocity){
controle.down(velocity);
}
public void left(int velocity){
controle.left(velocity);
}
public void right(int velocity){
controle.right(velocity);
}
public void forward(int velocity){
controle.forward(velocity);
}
public void back(int velocity){
controle.back(velocity);
}
public void turboBoost(){
controle.turboBoost();
}
public static void main(String[] args) {
SpaceShipDelegation nesa = new SpaceShipDelegation("NESA");
nesa.up(111);
}
}
protected关键字
package com.JavaSE02.demo08.demo01;
//protected关键字的小案例(使用频率较少)
public class Orc extends Villain{
private int orcNumber;
public Orc(String name,int orcNumber) {
super(name);
this.orcNumber=orcNumber;
}
public void change(String name,int orcNumber){//表示只有同包下和子类能够改变其的值
super.setName(name);//在改变的时候,调用父类的protected接口
this.orcNumber=orcNumber;
}
public String toString(){
return "Orc"+orcNumber+" : "+super.toString();
}
public static void main(String [] args){
Orc orc = new Orc("Limburger",12);
System.out.println(orc);
orc.change("Bob",19);
System.out.println(orc);
}
}
class Villain{
private String name;
public Villain(String name){
this.name=name;
}
public String toString(){
return "I'm a Villain and my name is "+name;
}
protected void setName(String name){
this.name=name;
}
}
final关键字
final关键字可应用在变量成员、方法成员和类中;
final变量:final用在基本数据类型上面,表示是常量;如果数据是引用类型的情况下,使用final,那么是指它的引用是不变的,引用的地址是不变的,引用对象本身是可以改变的;使用final告诉程序员这个成员是不可改变的;
package com.JavaSE02.demo09.demo01;
import java.util.Arrays;
import java.util.Random;
public class FinalDate {
private static Random rand =new Random(47);
private String id;
public FinalDate(String id){
this.id=id;
}
private final int valueOne=9;
private static final int VALUE_TWO=99;
public static final int VALUE_THREE=39;
private final int i4=rand.nextInt(20);
static final int INT_5=rand.nextInt(20);
private Value v1=new Value(11);
private final Value v2 = new Value(22);
private static final Value VAL_3=new Value(33);//satic只实例化一次
private final int[] a={1,2,3,4,5,6};
public String toString(){
return id+": i4= "+i4+", INT_5= "+INT_5;
}
public static void main(String[] args) {
FinalDate hh = new FinalDate("hh");
System.out.println(hh);
// hh.valueOne=19;这是不能进行赋值的,不可改变的
hh.v2.i++;//这个对象的引用不能改变,但引用里的值是可以改变的
hh.v1=new Value(33);//v1是实例成员,可以改变其引用
for (int i = 0; i < hh.a.length; i++) {
hh.a[i]=hh.a[i]++;//对象的引用的值是可以改变的;
}
System.out.println(hh);
System.out.println("Creating new FinalData");
FinalDate fd2 = new FinalDate("fd2");
System.out.println(fd2);
}
}
class Value{
int i;
public Value(int i){
this.i=i;
}
}
final方法:在设计上,想要明确指定这个方法是不能子类被重写的,就把这个方法定义成final
package com.JavaSE02.demo09.demo03;
public class FinalOverridingIllusion {
public static void main(String[] args) {
OverridingPrivatge2 overridingPrivatge2 = new OverridingPrivatge2();
overridingPrivatge2.f();
overridingPrivatge2.g();
OverriedingPrivate overriedingPrivate = overridingPrivatge2;//这不能调用f(),g()方法了
WithFinals wf =overriedingPrivate;
}
}
class WithFinals{
private final void f(){//这样写是没有意义的,private就相当于final的作用
System.out.println("WithFinals,f()");
}
private void g(){
System.out.println("WithFinals,g()");
}
}
class OverriedingPrivate extends WithFinals{
private final void f(){
System.out.println("OverriedingPrivate,f()");
}
private void g(){
System.out.println("OverriedingPrivate,g()");
}
}
class OverridingPrivatge2 extends OverriedingPrivate{
final void f(){
System.out.println("OverriedingPrivate2,f()");
}
void g(){
System.out.println("OverriedingPrivate2,g()");
}
}
final类:表示这个类不可被继承
package com.JavaSE02.demo09.demo04;
/**
* @program: bases
* @description:
* @author: LJC
* @create: 2020-04-14 15:14
**/
public class Jurassic {
public static void main(String[] args) {
Dinosaur dinosaur = new Dinosaur();
dinosaur.f();//能用,但是不能继承
}
}
final class Dinosaur{
int i=7;
int j=1;
SmallBrain x=new SmallBrain();
void f(){}
}
class SmallBrain{
}
//class subDinosaur extends Dinosaur{} 这是无法继承的 因为 Dinosaur final ;这种是出于安全性的考虑
继承与初始化
package com.JavaSE02.demo10.demo01;
/**
* 一开始找到主程序main方法开始加载,先初始化父类的静态变量,然后初始化子类的静态变量,然后回到main方法里输出语句,执行new Beetle()->调用子类构造器,但执行子类构造器之前
* 会先执行父类的构造器,然后回到子类执行构造器,先把实例成员创建,再执行构造器里内容;
*/
public class Beetle extends Insect {
private int k=printInt("Beetle.k Initialized");
public Beetle(){
System.out.println("k = "+k);
System.out.println("j = "+j);
}
private static int x2=printInt("static Beetle.x2 Initialized");
public static void main(String[] args) {
System.out.println("Beetle constructor");
Beetle beetle = new Beetle();
}
}
class Insect{
private int i=9;
protected int j;
Insect(){
System.out.println("i="+i+",j="+j);
j=39;
}
private static int x1=printInt("static Insect.x1 Initialized");
static int printInt(String s){
System.out.println(s);
return 47;
}
}