多态
8.3构造器和多态
- 尽管构造器并不具有多态性(它们实际上是static方法,只不过该static声明是隐式的)
- 构造器调用顺序:
- 调用基类构造器.
- 按声明顺序调用成员初始化方法.
- 调用导出类构造器主体.
- 上2初始化顺序并不完整
- 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零.
- 如前所述的那样调用基类构造器.
- 按声明顺序调用成员初始化方法.
- 调用导出类构造器主体.
//本例中存在两个知识点
//1. 如果要调用构造器内部的一个动态绑定的方法,就要用到那个方法的覆盖后的定义.
//2. 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的零.
//即初始化radius为0
class Glyph{
void draw(){
print("Glyph.draw()");
}
Glyph(){
print("Glyph() before draw()");
draw();
print("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
print("RoundGlyph.draw(). radius = " + radius);
}
void draw(){
print("RoundGlyph.draw().radius" + radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(5);
}
}/*Ouput:
Glyph() before, radius = 0
Glyph() after draw ()
RoundGlyph.RoundGlyph(), radius = 5
- 因此编写构造器时有一条有效准则:”用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其他方法”.
- 在构造器内唯一能够安全调用的那些方法时基类汇总的final方法(也适用private方法,它们自动属于final方法).
- 用继承表达行为间的差异,并用字段表达状态上的变化.附代码
class Actor{
public void act(){}
}
class HappyActor extends Actor{
public void act(){
print("HappyActor");
}
}
class SadActor extends Actor{
public void act(){
print("SadActor");
}
}
class Stage{
private Actor actor = new HappyActor();
public void change(){
actor = new SadActor();
}
public void performPlay(){
actor.act();
}
}
public class Transmogrify {
public static void main(String[] args) {
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
}
接口
9.1抽象类和抽象方法
- 如果从一个抽象类继承,并想创建该新类的对象,那么就必须为基类中的所有抽象方法提供定义.
- 这个题比较有意思我写下来.
创建一个不包含任何方法的抽象类,从哪里导出一个类,并添加一个方法.创建一个静态方法,他可以接收指向基类的引用,将其向下转型到导出类,然后再调用该静态方法,在main()中,展现它的运行情况.然后,为基类中的方法加上abstract声明,这样就不再需要进行向下转型.
abstract class Dad {}
class Son extends Dad {
protected void print() { System.out.println("Son"); }
}
abstract class SecondDad {
abstract protected void print();
}
class SecondSon extends SecondDad {
protected void print() { System.out.println("SecondSon"); }
}
public class Ja9_1_4 {
public static void testPrint(Dad d) {
((Son)d).print();//it's necessary
}
public static void secondTestPrint(SecondDad sd) {
sd.print();//don't need ((SecondSon)sd)
}
public static void main(String[] args) {
Son s = new Son();
Ja9_1_4.testPrint(s);
SecondSon ss = new SecondSon();
Ja9_1_4.secondTestPrint(ss);
}
}
- 续接口,接口中在jdk1.8后可以default声明关键字
9.2 接口
- Interface关键字使抽象的概念更向前迈进了一步.abstract关键字允许人们在类中创建一个或多个没有任何定义的方法–提供了接口部分,但是没有提供任何相应的具体实现,这些实现是由类的继承者创建的.
Interface这个关键字产生了一个完全抽象的类,他根本就没有提供任何具体实现.他允许创建者确定方法名 参数列表和返回类型,但是没有任何方法体.接口只提供了形式,而未提供任何具体实现.
- interface不仅仅是一个极度抽象的类,因为它允许人们通过创建一个能够被向上转型为多种基类的类型,来实现某种类似多重继变种的特性.
- 就像类一样,可以在interface关键字前面添加public关键字,如果不添加public关机找你,则它只有包访问权限,这样它就只能在同一个包内可用.接口也可以包含域,但是这些域隐式地是static和final的.
- 可以选择在接口中显式地方法声明为public的,但即使你不这么做,他们也是public的.
9.3完全耦合
- 用代码来解释一下耦合关系(刚开始没有看懂第二天又看才看懂)
//看两点
//1. class Processor 而不是 interface Processor(现象:完全耦合.造成应用领域太小)
//2. //如果Process是一个接口,那么这些限制就会变得松动,是的你可以复用结构该接口的Apply.process().
class Processor{//public interface Processor{String name(); Object process(Object input);}
public String name(){
return getClass().getSimpleName();
}
Object process(Object input){
return input;
}
}
class Upcase extends Processor{
String process(Object input){
return ((String)input).toUpperCase();
}
}
class Downcase extends Processor{
String process(Object input){
return ((String)input).toLowerCase();
}
}
class Splitter extends Processor{
String process(Object input){
// The split() argument divides a String into pieces;
return Arrays.toString(((String)input).split(" "));
}
}
//现在我们发现了一组电子滤波器 看起来是和上面的差不多,但是我们不能够取用主方法里面的Apply.process()方法
//那么通过下面的代码就可以看出来 这样写代码的复用性太差.
public class Waveform {
private static long counter;
private final long id = counter++;
public String toString(){
return "Waveform "+ id;
}
}
public class Filter {
public String name(){
return getClass().getSimpleName();
}
public Waveform process(Waveform input){
return input;
}
}
public class LowPass extends Filter {
double cutoff;
public LowPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;//Dummy processing
}
}
public class HighPass extends Filter {
double cutoff;
public HighPass(double cutoff){
this.cutoff = cutoff;
}
public Waveform process(Waveform input){
return input;
}
}
public class BandPass extends Filter {
double lowCutoff,highCutoff;
public BandPass(double lowCut,double highCut){
lowCutoff = lowCut;
highCutoff = highCut;
}
public Waveform Process(Waveform input){
return input;
}
}
//这样,创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式
public class Apply {
public static void process (Processor p,Object s){
print("Using Processor " + p.name());
print(p.process(s));
}
public static String s = "Disagreement with beliefs is by definition incorrect";
public static void main(String[] args){
process(new Upcase(),s);
process(new Downcase(),s);
process(new Splitter(),s);
}
}
- 解耦 适配器模式
class FilterAdapter implements Process{
Filter filter;
public FilterAdapter(Filter filter){
this.filter = filter;
}
public String name(){
return filter.name();
}
public Waveform process (Object input){
return filter.process((Waveform)input);
}
}
public class FilterProcess{
public static void main(String[] args){
Waveform w = new Waveform();
Apply.process(new FilterAdapter(new LowPass(1.0)),w);
Apply.process(new FilterAdapter(new HighPass(2.0)),w);
Apply.process(new FilterAdapter(new BandPass(3.0,4.0)),w);
}
}
9.4Java中的多重继承
- 注意一点implements关键字之后,可以继承多个接口,并可以向上转型为每个接口.
9.5通过继承来扩展接口
interface Monster{
void mence();
}
interface DangeousMonster extends Monster{
void destroy();
}
9.7接口中的域
- 接口中的域隐式地是static和final的
9.9接口与工厂(难点与重点)可以说是必知必会的东西
- 文字描述:接口时实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法设计模式.
- 这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象.理论上,通过这种方式,我们的代码将完全与接口的实现分离,这就使得我们可以透明地将某个实现替换为另一个实现.
package cn.itcast.zhuofai730.demo9_9;
import java.util.ServiceConfigurationError;
import static cn.itcast.zhuofai730.util.Print.print;
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
Implementation1(){}//Package access
public void method1(){print("Implementation1 method1");}
public void method2(){
print("Implementation method2");
}
}
class Implementation1Factory implements ServiceFactory{
public Service getService(){
return new Implementation1();
}
}
class Implementation2 implements Service{
Implementation2(){}//Pakage access
@Override
public void method1() {
print("Implementation2 method1");
}
@Override
public void method2() {
print("Implementation2 method2");
}
}
class Implementation2Factory implements ServiceFactory{
public Service getService(){
return new Implementation2();
}
}
public class Factories {
public static void serviceConsumer(ServiceFactory fact){
Service s = fact.getService();
s.method1();
s.method2();
}
public static void main(String[] args) {
serviceConsumer(new Implementation1Factory());
//Implementations are completely interchangeable;
serviceConsumer(new Implementation2Factory());
}
}
number two program
package cn.itcast.zhuofai730.demo9_9;
import static cn.itcast.zhuofai730.util.Print.print;
interface Game{boolean move();}
interface GameFactory {Game getGame();}
class Checkers implements Game{
private int moves = 0;
private static final int MOVES = 3;
public boolean move(){
print("Checker move" + moves);
return ++moves != MOVES;
}
}
class CheckersFactory implements GameFactory{
public Game getGame(){
return new Checkers();
}
}
class Chess implements Game{
private int moves = 0;
private static final int MOVES = 4;
public boolean move(){
print("Chess move "+ moves);
return ++moves != MOVES;
}
}
class ChessFactory implements GameFactory{
public Game getGame(){
return new Chess();
}
}
public class Games {
public static void playGame(GameFactory factory){
Game s = factory.getGame();
while(s.move())
;
}
public static void main(String[] args) {
playGame(new CheckersFactory());
playGame(new ChessFactory());
}
}