声明:本例子来自程杰先生的《大话设计模式》。原书是用C#语言表达的,我现在将它改造成java语言。
因为我熟悉C++,java,C#,后续课程我将描述清楚他们之间的区别。我将用同样的例子描述一遍。
本例子是要学生明白java核心内容。引导学生进一步学习高级java。包括:
1、java程序基本结构
2、包
3、普通类、构造函数、属性、属性访问函数、类的封装、类的抽象过程
4、抽象类
5、接口
6、this
7、super
8、static
一、简单的java程序:只显示一个对话框
import javax.swing.JOptionPane;
public class Example
{
public static void main(String[] args)
{
JOptionPane.showMessageDialog(null, "喵");
}
}
二、用函数的形式设计,用到static静态函数。
import javax.swing.JOptionPane;
public class Example
{
static String Shout()
{
return "喵";
}
public static void main(String[] args)
{
JOptionPane.showMessageDialog(null, Shout());
}
}
三、进一步封装成“猫”类。用到构造函数、属性
import javax.swing.JOptionPane;
class Cat {
private String name = "";//私有属性
public Cat()//构造函数
{
this.name = "无名";
}
public Cat(String name)//构造函数重载
{
this.name = name;
}
public String Shout()
{
return "我的名字叫"+name+"喵";
}
}
public class Example
{
public static void main(String[] args)
{
Cat cat = new Cat("咪咪");
JOptionPane.showMessageDialog(null, cat.Shout());
}
}
四、对“猫”类进行叫声次数的限制。用到属性访问函数
import javax.swing.JOptionPane;
class Cat {
private String name = "";
private int shoutNum = 3;
public int getShoutNum() //属性访问函数
{
return shoutNum;
}
public void setShoutNum(int shoutNum) //属性访问函数,对叫声次数进行限制
{
if(shoutNum <= 10)
this.shoutNum = shoutNum;
else
shoutNum = 10;
}
public Cat()
{
this.name = "无名";
}
public Cat(String name)
{
this.name = name;
}
public String Shout()
{
String result = "";
for(int i = 0; i< shoutNum;i++)//叫那么多次
{
result += " 喵";
}
return "我的名字叫"+name+result;
}
}
public class Example
{
public static void main(String[] args)
{
Cat cat = new Cat("小咪");
cat.setShoutNum(5);
JOptionPane.showMessageDialog(null, cat.Shout());
}
}
五、抽象。如果还有很多动物呢?比如说,增加Dog,Cattle,Sheep... ...
因此我们对动物进行抽象成Animal类。
public class Animal
{
protected String name = "";
protected int shoutNum = 3;
public int getShoutNum() {
return shoutNum;
}
public void setShoutNum(int shoutNum) {
this.shoutNum = shoutNum;
}
public Animal(String name)
{
this.name = name;
}
Animal()
{
this.name = "无名";
}
//Animal()
//{
// this("无名");
//}
}
猫就可以继承于Animal了。用到super,调用父类的构造函数
import javax.swing.JOptionPane;
class Cat extends Animal
{
public Cat()
{
super();
}
public Cat(String name)
{
super(name);
}
public String Shout()
{
String result = "";
for(int i = 0; i< shoutNum;i++)
{
result += " 喵";
}
return "我的名字叫"+name+result;
}
}
public class Example
{
public static void main(String[] args)
{
Cat cat = new Cat( );
cat.setShoutNum(5);
JOptionPane.showMessageDialog(null, cat.Shout());
}
}
六、接下来增加Dog类。
public class Dog extends Animal
{
public Dog()
{
super();
}
public Dog(String name)
{
super(name);
}
public String Shout()
{
String result = "";
for(int i = 0; i< shoutNum;i++)
{
result += " 旺";
}
return "我的名字叫"+name+result;
}
}
public class Example
{
public static void main(String[] args)
{
Cat cat = new Cat( "咪咪");
cat.setShoutNum(5);
JOptionPane.showMessageDialog(null, cat.Shout());
Dog dog = new Dog("旺财");
dog.setShoutNum(2);
JOptionPane.showMessageDialog(null, dog.Shout());
}
}
七、因为Dog,Cat类都有Shout()方法。我们可以进一步对Animal类进行抽象。
public class Animal
{
protected String name = "";
protected int shoutNum = 3;
public int getShoutNum() {
return shoutNum;
}
public void setShoutNum(int shoutNum) {
this.shoutNum = shoutNum;
}
public Animal(String name)
{
this.name = name;
}
Animal()
{
this.name = "无名";
}
//Animal()
//{
// this("无名");
//}
public String Shout()//java中没有virtual关键字,因为它本来就是默认虚的。
{
return " ";
}
}
在main写成:(可以体会到多态)
public class Example
{
public static void main(String[] args)
{
Animal [] arrayAnimal= new Animal[5];
arrayAnimal[0] = new Cat("小花");
arrayAnimal[1] = new Dog("阿毛");
arrayAnimal[2] = new Dog("小黑");
arrayAnimal[3] = new Cat("娇娇");
arrayAnimal[4] = new Cat("咪咪");
for(Animal animal : arrayAnimal)
{
JOptionPane.showMessageDialog(null, animal.Shout());
}
}
}
八、每个Animal类都要叫,只是叫声不同而已。因此我们可以进一步对Animal类进行抽象。改成抽象类。
修改Animal 类:
public abstract class Animal
{
protected String name = "";
protected int shoutNum = 3;
public int getShoutNum() {
return shoutNum;
}
public void setShoutNum(int shoutNum) {
this.shoutNum = shoutNum;
}
public Animal(String name)
{
this.name = name;
}
Animal()
{
this("无名");
}
public String Shout()
{
String result = "";
for(int i = 0; i< shoutNum;i++)
{
result += getShoutSound()+". ";
}
return "我的名字叫"+name+result;
}
protected abstract String getShoutSound();//具体怎么叫还不清楚,留给子类去实现它。
}
Dog类实现getShoutSound() :
public class Dog extends Animal
{
public Dog()
{
super();
}
public Dog(String name)
{
super(name);
}
public String getShoutSound() {
// TODO Auto-generated method stub
return "汪";
}
}
Cat类实现getShoutSound() :
public class Cat extends Animal
{
public Cat()
{
super();
}
public Cat(String name)
{
super(name);
}
public String getShoutSound()
{
return "喵";
}
}
main函数不用改变,编译运行,结果一样。
九、如果我们增加“机器猫”、“孙悟空”呢?他们分别继承于Cat、Monkey类!而且都会变法术!所以用接口解决这种行为的抽象。
public interface IChange
{
String ChangeThing(String thing);
}
public class Monkey extends Animal
{
public Monkey()
{
super();
}
public Monkey(String name)
{
super(name);
}
public String getShoutSound() {
return "吱";
}
}
机器猫继承于Cat,还是实现IChange
public class MachineCat extends Cat implements IChange
{
MachineCat()
{
super();
}
MachineCat(String name)
{
super(name);
}
public String ChangeThing(String thing)
{
return super.Shout() + "我有万能的口袋,我可变出:"+thing;
}
}
石猴继承于Monkey,还是实现IChange
public class StoneMonkey extends Monkey implements IChange
{
StoneMonkey()
{
super();
}
StoneMonkey(String name)
{
super(name);
}
public String ChangeThing(String thing)
{
return super.Shout() + "我七十二变,我可变出:"+thing;
}
}
进一步体现多态:
public class Example
{
public static void main(String[] args)
{
MachineCat mcat = new MachineCat("叮当");
StoneMonkey wukong = new StoneMonkey("孙悟空");
IChange[] array = new IChange[2];//进一步体现多态
array[0] = mcat;
array[1] = wukong;
JOptionPane.showMessageDialog(null, array[0].ChangeThing("各种各样的东西!"));
JOptionPane.showMessageDialog(null, array[1].ChangeThing("各种各样的东西!"));
}
}
总结:
Java中绑定的所有方法都采用后期绑定技术,除非一个方法已被声明成final。这意味着我们通常不必决定是否应进行后期绑定——它是自动发生的。知道Java里绑定的所有方法都通过后期绑定具有多形性以后,就可以相应地编写自己的代码,令其与基础类沟通。此时,所有的衍生类都保证能用相同的代码正常地工作。或者换用另一种方法,我们可以“将一条消息发给一个对象,让对象自行判断要做什么事情。”
包含了抽象方法的一个类叫作“抽象类”。如果一个类里包含了一个或多个抽象方法,类就必须指定成abstract(抽象)。否则,编译器会向我们报告一条出错消息。若一个抽象类是不完整的,那么一旦有人试图生成那个类的一个对象,编译器又会采取什么行动呢?由于不能安全地为一个抽象类创建属于它的对象,所以会从编译器那里获得一条出错提示。通过这种方法,编译器可保证抽象类的“纯洁性”,我们不必担心会误用它。如果从一个抽象类继承,而且想生成新类型的一个对象,就必须为基础类中的所有抽象方法提供方法定义。如果不这样做(完全可以选择不做),则衍生类也会是抽象的,而且编译器会强迫我们用abstract关键字标志那个类的“抽象”本质。即使不包括任何
abstract方法,亦可将一个类声明成“抽象类”。如果一个类没必要拥有任何抽象方法,而且我们想禁止那个类的所有实例,这种能力就会显得非常有用。
“interface”(接口)关键字使抽象的概念更深入了一层。我们可将其想象为一个“纯”抽象类。它允许创建者规定一个类的基本形式:方法名、自变量列表以及返回类型,但不规定方法主体。接口也包含了基本数据类型的数据成员,但它们都默认为static和final。接口只提供一种形式,并不提供实施的细节。接口这样描述自己:“对于实现我的所有类,看起来都应该象我现在这个样子”。因此,采用了一个特定接口的所有代码都知道对于那个接口可能会调用什么方法。这便是接口的全部含义。
所以我们常把接口用于建立类和类之间的一个“协议”。有些面向对象的程序设计语言采用了一个名为“protocol”(协议)的关键字,它做的便是与接口相同的事情。为创建一个接口,请使用interface关键字,而不要用class。与类相似,我们可在interface关键字的前面增加一个public关键字(但只有接口定义于同名的一个文件内);或者将其省略,营造一种“友好的”状态。
为了生成与一个特定的接口(或一组接口)相符的类,要使用implements(实现)关键字。我们要表达的意思是“接口看起来就象那个样子,这儿是它具体的工作细节”。除这些之外,我们其他的工作都与继承极为相似。