``一 java基础篇
public class Hello {
}
ctrl+/:注释 Alt+/:代码提示 shift+向下键:选择下一行
“”中为字符串 全选+Tab将代码缩进
import java.util.Scanner;
public class Hello {
}
import java.util.Scanner;
public class Hello {
// Scanner in = new Scanner(System.in);
// System.out.println(in.nextLine());
System.out.println(“1+2=”+(1+2));
}
}
用 + 可以将字符串连接
import java.util.Scanner;
public class Var {
}
import java.util.Scanner;
public class Var {
}
}
import java.util.Scanner;
public class Var {
}
}
}
//java中两个整数相除得数一定是整数,如果一个是浮点数则结果也为浮点数(double型)
单目取正(负):a*-b 自右向左顺序
强制类型转换:转换成整型 : (int)(*)将右侧一堆转换成左侧
Scanner in = new Scanner(System.in);
System.out.print(“请输入票面金额”);
int amount = in.nextInt();
System.out.print(amount >= 10); 大于等于10输出true
所有关系运算符优先级比算术优先级翁恺java零基础入门低但比赋值优先级高
判断是否相等的运算符==,!=的优先级比其他的低 ,而连续的关系运算是从左到右进行的
判断两个浮点数是否相等: Math.abs(f1-f2)<1e-6
import java.util.Scanner;
public class Var {
}
}
如果要模拟很大次数的循环,可以模拟较少的循环进行推断。
猜数字小游戏:
import java.util.Scanner;
public class Var {
}
}
整数分解:
import java.util.Scanner;
public class Var {
}
}
对于一个循环体,有固定执行次数,用for循环。循环必须要执行一次用do-while。其他情况用while
for(i=0;i<n;i++){}循环n次 factor *=i factor 赋值于1(阶乘)
题干:判断一个数是不是素数
import java.util.Scanner;
public class Var {
}
}
逻辑运算优先级: !>&&> || 单目运算符,赋值运算符自右向左
题干:枚举法:
import java.util.Scanner;
public class Var {
}
}
题干:求和:
import java.util.Scanner;
public class Var {
}
辗转相除法:求两个数最大公约数
import java.util.Scanner;
public class Var {
}
使用数组求平均数:遍历:
package array;
import java.util.Scanner;
public class Arry {
}
输出结果a[0]=b[0]与 int i = j;(i与j占用两个独立的地址)不同, []a与[]b均为new出来数组的管理者,所以b[0]重新赋值两个a[0,b[0]均发生变化。
输出结果True,两个数组每个位置对应元素相同。
投票游戏:按-1结束,统计0-9输入同一数字的次数:
package array;
import java.util.Scanner;
public class Main{
}
}
}
判断数字是否在数组中:
import java.util.Scanner;
public class Var {
}
判断一个数是否是素数更快的数学方法:
构造前1-100之内素数表:(思路:素数的倍数取反,输出取正的结果)
import java.util.Scanner;
public class Var {
}
}
构造前50个素数:(思路:判断是否能被已知的且小于x的素数整除)
import java.util.Scanner;
public class Var {
}
}
字符:
char c = (char)(‘a’-‘A’+‘A’); //输出c为a
System.out.println(‘汉’>‘A’) //输出结果为true,汉字比所有英文字母要大
System.out.println(Character.tolowerCase(‘I’)); //将大写字母转换成小写字母
character.isDigit(‘1’) //判断是不是数字
Interger.MAX_VALUE 2^31-1 —32bit----整型4个字节
Math.round() //做四舍五入
Math.random() //生成一个0-1之间的随机数【0-1)
Math.pow(2,3.2) //表示2的3.2次方
字符串变量: String s = new String(“a string”); //字符串变量是字符串的管理者而不是所有者
System.out.println(“abc”+12+24); //输出abc1224, 因为从左至右加号会先将12变为字符串形式,再+24
s=in.next() //如果用空格分隔每一个单词(a string),只能都读进来一个单词(a)
System.out.println(s.equals(“a”)); //判断字符串是否相等必须用equals不能用 == ,==是判断是否指向同一位置
字符串操作:
String s = “Hello”;
s.lengeh(); --> 这里的 .length() 是一个操作
s.charAt(0) //取出第0个字符是H
s.substring(2,4) //输出ll ,取出的是从第二个到第四个之前的部分字符串
int loc = s.indexOf(‘l’) //取出的第一个 l 的位置
System.println(s.indexOf(‘l’,loc+1)) //取出的第二个 l 的位置
函数形式判断是不是素数: //能否被小于他的数整除
import java.util.Scanner;
import java.util.Scanner;
public class Var {
public static boolean isPrime(int j)
{
boolean isPrime = true;
for(int i=2 ; i<j ; i++)
{
}
}
只能传值给函数,不能改变主函数的变量
二 面向对象程序设计 --java
1.用类制造对象
封装:把数据和对数据所有的操作放在一起
2.定义类:
package VendingMachine;
public class VendingMachine {
int price = 80;
int balance;
int total;
void showPrompt()
{
System.out.print(“请投入货币”);
}
void insertMoney(int amount)
{
balance = balance + amount;
}
void showBalance()
{
System.out.print(“余额:”+balance);
}
void getFood()
{
if( balance > price )
}
成员函数:
public class VendingMachine {
int price = 80;
int balance;
int total;
void showPrice(int price)
{
this.price = price ; // 这里的this可以直接指向上面赋值80的price,而不加this只能指向离他最近的
} 传入函数括号内的price
在一个成员函数内部调用自己其他成员函数可以不加this
关于初始化:java会给成员变量一个默认的零值
构造函数:
public class VendingMachine {
int price = 80;
int balance = f();
int total;
void showPrompt()
{
System.out.print(“请投入货币”);
}
int f()
{
return 10;
}
VendingMachine() (1) //friendly位于同一个包的类可以访问
{
total = 0; //构造函数,不能返回任何值
}
VendingMachine(int price) //重载时访问 (2)
{
this(); //在构造函数里调用其他构造函数,只能在构造函数里出现,且只能使用一次
this.price = price;
}
void insertMoney(int amount)
{
balance = balance + amount;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
VendingMachine vm = new VendingMachine(); //走到这步后运行到(1)处
VendingMachine vm = new VendingMachine(100); //走到这步后运行到(2)处 重载
vm.showPrompt();
vm.insertMoney(100);
vm.showBalance();
vm.getFood();
}
对象的交互: 时钟*
package clock;
public class Dispaly {
private int value = 0;
private int limit = 0;
public Dispaly(int limit)
{
this.limit = limit;
}
public void increase()
{
value++;
if(value == limit)
{
value = 0;
}
}
int getValue()
{
return(value);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Dispaly d1 = new Dispaly(24);
for(;😉
{
d1.increase();
System.out.println(d1.getValue());
}
public class Clock {
private Dispaly hour = new Dispaly(24); //private是私有的,只有在自己的类里面才能访问
private Dispaly minute = new Dispaly(60);
public void start()
{
while(true) {
minute.increase();
if(minute.getValue() == 0)
{
hour.increase();
}
System.out.printf("%02d:%02d ",hour.getValue(),minute.getValue());
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Clock c = new Clock();
c.start();
}
}
一个public类必须在自己的文件里面,一个文件只能有一个public类
java里面每一个点代表一级目录,包可以包含一个更深的包
类变量
package clock;
public class Dispaly {
private int value = 0;
private int limit = 0;
private static int step = 1;
public Dispaly(int limit)
{
this.limit = limit;
}
public void increase()
{
value++;
if(value == limit)
{
value = 0;
}
}
int getValue()
{
return(value);
}
public static void f()
{
错误示范:value++; //不可行的,static里不可以直接访问一个non-static的变量
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
容器
实现一个日记本
日记本的功能:
根据功能相应的接口设计:
package coumn;
import java.util.ArrayList; //ArrayList容量是无限的
public class Coumn {
private ArrayList notes = new ArrayList ();
public void add(String s)
{
notes.add(s);
}
public void add(String s,int location)
{
notes.add(location,s); //将String s插入loction这个位置
}
public int getSize()
{
return notes.size() ; //返回容器的大小
}
public String getNote(int index)
{
return notes.get(index); //输入的index(在容器中的位置),返回位置上的String
}
public void removeNote(int index)
{
notes.remove(index); //remove方法会把刚刚删掉的返回回来,如果index越界则抛出异常
}
public String[] list()
{
return new String[10];
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Coumn c1 = new Coumn();
c1.add(“first”);
c1.add(“second”);
c1.add(“third”,1);
System.out.println(c1.getNote(0));
System.out.println(c1.getNote(1));
}
}
日记本成品
package coumn;
import java.util.ArrayList;
public class Coumn {
private ArrayList notes = new ArrayList ();
public void add(String s)
{
notes.add(s);
}
public void add(String s,int location)
{
notes.add(location,s);
}
public int getSize()
{
return notes.size() ;
}
public String getNote(int index)
{
return notes.get(index);
}
public void removeNote(int index)
{
notes.remove(index);
}
public String[] list()
{
String []a = new String[notes.size()]; //string数组的长度是容器的长度
//for(int i=0;i<notes.size();i++)
//{
//a[i] = notes.get(i);
//}
notes.toArray(a); //避免使用循环,直接将notes中每个元素放入数组a;
return a;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Coumn c1 = new Coumn();
c1.add(“first”);
c1.add(“second”);
c1.add(“third”,1);
System.out.println(c1.getNote(0));
System.out.println(c1.getNote(1));
System.out.println(c1.getNote(2));
System.out.println(c1.getSize());
String []b = c1.list(); //直接调用c1的list方法
for(String s:b) //使用for-each循环取出数组b中的元素
{
System.out.println(s);
}
}
对象数组
对象数组每一个元素都是对象的管理者,而非对象本身。如果对象数组没有给予一个元素创建出来的对象,则指向null
String数组就是对象数组,因为String变量本身就是对象需要new出来的,而普通数组int则不同
,整型变量不需要new
package coumn;
import java.util.ArrayList;
class Value //新构造一个Value类
{
private int i ;
public void set(int i)
{
this.i=i;
}
public int get()
{
return i;
}
public String toString()
{
return ;
}
}
public class Coumn {
private ArrayList notes = new ArrayList ();
public void add(String s)
{
notes.add(s);
}
public void add(String s,int location)
{
notes.add(location,s);
}
public int getSize()
{
return notes.size() ;
}
public String getNote(int index)
{
return notes.get(index);
}
public void removeNote(int index)
{
notes.remove(index);
}
public String[] list()
{
String []a = new String[notes.size()];
//for(int i=0;i<notes.size();i++)
//{
//a[i] = notes.get(i);
//}
notes.toArray(a);
return a;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Coumn c1 = new Coumn();
c1.add(“first”);
c1.add(“second”);
c1.add(“third”,1);
System.out.println(c1.getNote(0));
System.out.println(c1.getNote(1));
System.out.println(c1.getNote(2));
System.out.println(c1.getSize());
String []b = c1.list();
Value []v1 = new Value[10]; //构造一个Value类的对象数组
for(int i = 0; i < 10 ;i++)
{
v1[i] = new Value(); //对象数组内每一个元素都需要一个管理者
v1[i].set(i); //将数组内每一个值传入i
}
for(Value a:v1) //这里的for-each循环是v1给a赋值的关系,a可以直接使用v1中的方法
{
System.out.println(a.get());
}
ArrayList b = new ArrayList();
b.add(“first”);
b.add(“second”);
for(String f:b)
{
System.out.println(f); //容器ArrayList也可以使用for-each循环
}
}
package coumn;
import java.util.ArrayList;
import java.util.HashSet;
class Value
{
private int i ;
public void set(int i)
{
this.i=i;
}
public int get()
{
return i;
}
public String toString()
//ArrayList<>与HashSet共同包含的功能都有String toString函数,此函数println 对象 ,会主动输出 i
//而新构造的对象函数本身内部没有封装过string tostring,需要自己构造
{
return(""+i);
}
}
public class Coumn {
private ArrayList notes = new ArrayList ();
public void add(String s)
{
notes.add(s);
}
public void add(String s,int location)
{
notes.add(location,s);
}
public int getSize()
{
return notes.size() ;
}
public String getNote(int index)
{
return notes.get(index);
}
public void removeNote(int index)
{
notes.remove(index);
}
public String[] list()
{
String []a = new String[notes.size()];
//for(int i=0;i<notes.size();i++)
//{
//a[i] = notes.get(i);
//}
notes.toArray(a);
return a;
}
HashSet集合
public static void main(String[] args) {
// TODO Auto-generated method stub
Value v2 = new Value();
v2.set(12);
System.out.println(v2);
HashSet s = new HashSet(); //HashSet代表集合
s.add(“first”);
s.add(“second”);
s.add(“third”);
System.out.println(s);
//输出 【first,second】 ,因为是集合,同理ArrayList可以以同样输出对象形式输出方括号。
System.out.println("…");
Value []v1 = new Value[10];
for(int i = 0; i < 10 ;i++)
{
v1[i] = new Value();
v1[i].set(i);
}
// for(Value a:v1)
// {
// System.out.println(a.get());
// }
//
}
Hash表
将金额对应得英文单词存在哈希表里,输入一个数字得到一个英文字符
package hash;
import java.util.HashMap;
import java.util.Scanner;
public class Coin {
private HashMap<Integer,String> coinnames= new HashMap<Integer,String>(); //哈希表
public Coin()
{
coinnames.put(1,“penny”);
coinnames.put(2,“dime”);
coinnames.put(5,“quarter”);
coinnames.put(10,“half-dolar”);
coinnames.put(10,“dolar”);
System.out.println(coinnames.keySet().size()); //输出哈希表里面元素的集合大小为四
System.out.println(coinnames);
//输出哈希表里面元素的集合,只有四个 “penny”, “dime”,“quarter”,“dolar”
输出 {1=penny, 2=dime, 5=quarter, 10=dolar} 四个键值对
}
for(int k : coinnames.keySet())
//遍历ArrayList与遍历HashSet都只需要直接for-each在输出即可。
//遍历哈希表则不同:需要先利用表得集合方法将(键值对中的键)赋值给K,再使用哈希表的get方法获取元素。
{
String z = coinnames.get(k);
System.out.println(z);
}
public String get(int amount)
{
if(coinnames.containsKey(amount)) //条件如果元素存在,则返回单词。
{
return coinnames.get(amount);
}
else
{
return “NOT FOUND”;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner c = new Scanner(System.in);
int amount = c.nextInt();
Coin c1 = new Coin();
System.out.println(c1.get(amount));
}
}
继承
实现一个可以装入DVD与CD的数据库
Database
package domb;
import java.util.ArrayList;
public class Database {
//private ArrayList CDlist= new ArrayList();
//private ArrayListDVDlist= new ArrayList();
private ArrayListItemlist= new ArrayList();
// public void add(CD cd)
// {
// CDlist.add(cd);
// }
// public void add(DVD dvd)
// {
// DVDlist.add(dvd);
// }
public void add(Item item)
{
Itemlist.add(item);
}
public void list()
{
for(Item item : Itemlist)
{
item.print();
}
// for(CD cd : CDlist)
// {
// cd.print();
// }
// for(DVD dvd : DVDlist)
// {
// dvd.print();
// }
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD(“panama”, “jack”, 6, 6, “IGNB”));
db.add(new CD(“banama”, “back”, 7, 6, “IGNB”));
db.add(new DVD(“ganama”, “back”, 8,“IGNB”));
db.list();
}
}
CD
package domb;
public class CD extends Item{
// private int playingTime;
// private boolean gotIt = false;
// private String comment;
// this.playingTime = playingTime;
// this.comment = comment;
}
public void print()
{
System.out.print(“CD:”);
super.print();
System.out.print(artist);
}
}
DVD
package domb;
public class DVD extends Item {
// private String title;
private String director;
// private int playingTime;
// private boolean gotIt = false;
// private String comment;
public DVD(String title, String director, int playingTime, String comment) {
super(title,playingTime,false,comment); //若super中没有传入参数(不管有没有super),都会调用父类中一个没有形参的构造器(类似于重载)
//super只能调用一次且只能在第一行
// this.title = title; //如果子类与父类有完全相同的变量,则父类变量会被隐藏起来
this.director = director;
// this.playingTime = playingTime;
// this.comment = comment;
}
public void print()
{
System.out.print(“DVD:”);
super.print();
}
Item Item是DVD与CD的父类
package domb;
public class Item {
private String title; //父类中的private,子类不能访问
private int playingTime;
private boolean gotIt = false;
private String comment;
public void print()
{
System.out.println(title+"😊;
}
public Item() {
super();
}
多态及向上造型
Item相当于一个多态变量,而add(new cd(,,))发生了向上造型
上图:String s = “hello”; //"hello"并没有被bye覆盖,而是s与hello之间断开,与bye进行连接
s = “bye”
造型
package domb;
public class Item {
private String title; //父类中的private,子类不能访问
private int playingTime;
private boolean gotIt = false;
private String comment;
public void print()
{
System.out.println(title+"😊;
}
public Item() {
super();
}
假设现有4个类:Person、Teacher、Student和PhDStudent。Teacher 和Student都是Person的子类,PhDStudent是Student的子类。以下的赋值语句哪些是合法的,为什么?
Person p1 = new Student();
Person p2 = new PhDStudent();
PhDStudent phd1 = new Student();
Teacher t1 = new Person();
Student s1 = new PhDStudent();
s1 = p1;
s1 = p2;
P1 = s1;
t1 = s1;
s1 = phd1;
Phd1 = s1;
合法的有:
Person p1 = new Student(); 子类对象赋值给父类变量
Person p2 = new PhDStudent(); 子类对象赋值给父类变量
Student s1 = new PhDStudent(); 子类对象赋值给父类变量
p1 = s1; 子类对象赋值给父类变量
不合法的有:
PhDStudent phd1 = new Student(); 父类对象不能直接赋值给子类变量
Teacher t1 = new Person(); 父类对象不能直接赋值给子类变量
s1 = p1; 父类对象不能直接赋值给子类变量
s1 = p2; 父类对象不能直接赋值给子类变量
t1 = s1; t1未被成功创建,且t1与s1的类型没有直接关系
s1 = phd1; phd1未被成功创建,若成功创建则合法
Phd1 = s1; phd1未被成功创建,且父类对象不能直接赋值给子类变量
多态:
for(Item item:Itemlist)
{
Item.print(); 声明类型:Item
System.out.println(); 动态类型:DVD CD Item.print(); 调用实际的动态类型
}
draw的函数有多个,这里shape调用会自动选择
类型系统----Object
package domb;
public class CD extends Item{
// private int playingTime;
// private boolean gotIt = false;
// private String comment;
// this.playingTime = playingTime;
// this.comment = comment;
}
public void print()
{
System.out.print(“CD:”);
//super.print();
System.out.print(artist);
}
}
如果要在VideoGame基础上增加一个BoardGame,可以选择一个更深的继承
城堡游戏–消除代码复制
package Ga;
import java.util.*;
// 以下为用户命令
public class Room {
public String description;
public Room northExit;
public Room southExit;
public Room eastExit;
public Room westExit;
}
城堡游戏–耦合和聚合
要评判某些设计比其他的设计优秀,就得定义一些在类的设计中重要的术语,以用来讨论 设计的优劣。对于类的设计来说,有两个核心术语:耦合和聚合。 耦合这个词指的是类和类之间的联系。之前的章节中提到过,程序设计的目标是一系列通 过定义明确的接口通信来协同工作的类。耦合度反映了这些类联系的紧密度。我们努力要获得 低的耦合度,或者叫作松耦合(loose coupling)。
耦合度决定修改应用程序的容易程度。在一个紧耦合的结构中,对一个类的修改也会导致 对其他一些类的修改。这是要努力避免的,否则,一点小小的改变就可能使整个应用程序发生 改变。另外,要想找到所有需要修改的地方,并一一加以修改,却是一件既困难又费时的事情。 另一方面,在一个松耦合的系统中,常常可以修改一个类,但同时不会修改其他类,而且 整个程序还可以正常运作。
本周会讨论紧耦合和松耦合的例子。 聚合与程序中一个单独的单元所承担的任务的数量和种类相对应有关,它是针对类或方法 这样大小的程序单元而言的理想情况下,一个代码单元应该负责一个聚合的任务(也就是说,一个任务可以被看作是 一个逻辑单元)。一个方法应该实现一个逻辑操作,而一个类应该代表一定类型的实体。聚合 理论背后的要点是重用:如果一个方法或类是只负责一件定义明确的事情,那么就很有可能在 另外不同的上下文环境中使用。遵循这个理论的一个额外的好处是,当程序某部分的代码需要 改变时,在某个代码单元中很可能会找到所有需要改变的相关代码段。
城堡游戏–封装
package Ga;
import java.util.*;
// 以下为用户命令
public class Room {
public String description;
private Room northExit;
private Room southExit;
private Room eastExit;
private Room westExit;
public String getExitDes (){ //解耦合
StringBuffer sb = new StringBuffer(); //相比于str+=更利于空间的利用
if(northExit != null)
sb.append(“north”);
if(eastExit != null)
sb.append(“east”);
if(southExit != null)
sb.append(“south”);
if(westExit != null)
sb.append(“west”);
return sb.toString(); //输出结构字符
}
public Room getExit(String direction)
{
Room ret = null;
if(direction.equals(“north”)){
ret = northExit;
}
if(direction.equals(“east”)){
ret = eastExit;
}
if(direction.equals(“south”)){
ret = southExit;
}
if(direction.equals(“west”)){
ret = westExit;
}
return ret; //输出下一个房间
}
//public void southExit(Object object, Room lobby, Room study, Room pub) {
// TODO Auto-generated method stub
}
可扩展性
package Ga;
import java.util.*;
// 以下为用户命令
}
public class Room {
public String description;
private Room northExit;
private Room southExit;
private Room eastExit;
private Room westExit;
private HashMap<String,Room> exists = new HashMap<String,Room>();
public Room(String description)
{
this.description = description;
}
public void setExits(String dir,Room room) 增强可扩展性,构造哈希表
{
exists.put(dir,room);
}
// public void setExits(Room north,Room east,Room south,Room west)
// {
// if(north != null)
// northExit = north;
// if(east != null)
// eastExit = east;
// if(south != null)
// southExit = east;
// if(west != null)
// westExit = west;
// }
public String getExitDes (){
StringBuffer sb = new StringBuffer();
for(String dir: exists.keySet() )
{
sb.append(dir); //增强可扩展性,添加房间可走的 方向
}
// if(northExit != null)
// sb.append(“norh”);
// if(eastExit != null)
// sb.append(“east”);
// if(southExit != null)
// sb.append(“south”);
// if(westExit != null)
// sb.append(“west”);
return sb.toString();
}
public Room getExit(String dir)
{
Room ret = null;
// if(direction.equals(“north”)){
// ret = northExit;
// }
// if(direction.equals(“east”)){
// ret = eastExit;
// }
// if(direction.equals(“south”)){
// ret = southExit;
// }
// if(direction.equals(“west”)){
// ret = westExit;
// } //增强可扩展性,获得该方向上房间
return exists.get(dir);
}
//public void southExit(Object object, Room lobby, Room study, Room pub) {
// TODO Auto-generated method stub
}
框架加数据
package Ga;
import java.util.*;
import java.util.HashMap;
public class Castle {
private Room currentRoom;
private HashMap<String,Handler> handlers = new HashMap<String,Handler>(); //将用户的命令转化为哈希表中的String,将接到命令以后的操作转化为哈希表中的Handler类中的函数
public Castle() {
createRooms();
handlers.put(“bye”, new HandlerBye(this)); //由于HandlerBye,HandlerHelp,HandlerGo中均有Castle属性,所以要在括号里加入this
handlers.put(“help”, new HandlerHelp(this));
handlers.put(“go”, new HandlerGo(this));
}
public void play(){
Scanner in = new Scanner(System.in);
while(true) {
String line = in.nextLine();
String[] words = line.split(" ");
Handler handler = handlers.get(words[0]); //取哈希表中键String为words[0]时的数值
String value = “”;
if(words.length>1)
{
value = words[1];
}
if(handler!=null) {
handler.docmd(value);
if ( handler.isBye()){
break;
}
// 以下为用户命令
// private void printHelp()
// {
//
// }
package Ga;
public class Handler { //所有Handler操作的父类
public void docmd(String k) {};
public boolean isBye() {return false;} ; //如果传入的值的键不是HandlerBye则返回false
public static void main(String[] args) {
// TODO Auto-generated method stub
public class HandlerBye extends Handler { // HandlerBye为Handler的子类执行用户输入bye时的操作
@override
public boolean isBye() {return true;} ; //继承了父类返回true
public static void main(String[] args) {
// TODO Auto-generated method stub
public class HandlerGo extends Handler{
public HandlerGo(Castle castle) {
super(castle);
}
@override
//public void docmd(String word)
//{
//Castle.goRoom(word);
//};
public static void main(String[] args) {
// TODO Auto-generated method stub
public class HandlerHelp extends Handler{
public HandlerHelp(Castle castle) {
super(castle);
}
@override
public void docmd(String k)
{
System.out.println(“迷路了吗?你可以做的命令有:go bye help”);
System.out.println(“如: go east”);
};
}
隐形耦合
现在的代码,如果增加新的命令,那么help所输出的内容就需要做变化,而help的输出内容目前是硬编码的。如何修改代码能实现help的输出内容与help的输出函数无关,使得新的命令加入的时候,help能自动输出新的内容
1、在Game类中增加一个接口,返回所有的指令
public Set getAllCmds(){
}
2、修改HandlerHelp中的输出代码
@Override
public void doCmd(String word) {
}
如何实现任意门?
如果想要实现任意门,即在某个房间,想要从某个出口出去,结果每次会走到不同的房间去。
如果要实现这样的任意门,整个程序的架构应该是怎样的?
如果任意门只是在这个房间的所有的门之间轮转,应该怎样实现?
// Game.java
public Game() {
…
handlers.put(“poll”, new HandlerPoll(this));
createRooms();
}
为此,需要创建相应的Handler子类,并重写doCmd(String word)来实现具体功能:
// HandlerPoll.java
public void doCmd(String word) {
game.pollRoom();
}
和HandlerGo类似,此功能需要调用game的相应方法来完成,所以还要在Game类中添加这个方法。其具体实现方式有两种:
在Room类中实现轮转
// Game.java
public void pollRoom() {
currentRoom.pollExit();
}
// Room.java
public void pollExit() {
// 实现轮转
}
在Game类中实现轮转
// Game.java
public void pollRoom() {
Room[] exitss = currentRoom.getExits();
// 实现轮转
}
// Room.java
public void getExits() {
return exits.values().toArray(new Room[0]);
}
优先选择方法1,因为它的耦合更松。但如果要求任意门能在整个城堡的所有的门之间轮转,方法1就不适用了,此时就只能使用方法2。
抽象与接口
在第一周就有一个Shape类的例子。这个类有很多的子类,每个子类也都实现了父类的方法。实际上父类Shape只是一个抽象的概念而并没有实际的意义。如果请你画一个圆,你知道该怎么画;如果请你画一个矩形,你也知道该怎么画。但是如果我说:“请画一个形状,句号”。你该怎么画?同样,我们可以定义Circle类和Rectangle类的draw(),但是Shape类的draw()呢?
Shape类表达的是一种概念,一种共同属性的抽象集合,我们并不希望任何Shape类的对象会被创建出来。那么,我们就应该把这个Shape类定义为抽象的。我们用abstract关键字来定义抽象类。抽象类的作用仅仅是表达接口,而不是具体的实现细节。抽象类中可以存在抽象方法。抽象方法也是使用abstract关键字来修饰。抽象的方法是不完全的,它只是一个方法签名而完全没有方法体。
如果一个类有了一个抽象的方法,这个类就必须声明为抽象类。如果父类是抽象类,那么子类必须覆盖所有在父类中的抽象方法,否则子类也成为一个抽象类。一个抽象类可以没有任何抽象方法,所有的方法都有方法体,但是整个类是抽象的。设计这样的抽象类主要是为了防止制造它的对象出来。
package shapes;
import java.awt.Graphics;
public abstract class Shape {
}
package shapes;
import java.awt.Graphics;
public class Circle extends Shape {
private int x;
private int y;
private int radius;
}
package shapes;
import java.awt.Graphics;
public class Triangle extends Shape {
private int[] x = new int[3];
private int[] y = new int[3];
}
如果shape为abstract类,则抽象得类无法实例化对象s,则s.draw无法实现。如果shape不为abstract,s.draw依然无法实现,因为draw函数没有函数体
数据与表现分离
Field只保存细胞的数据,cellMachine负责更新细胞的生存状态,view负责从field中取出细胞数据来paint
相比使用setAlive(boolean)函数,die()、reborn()两个函数其实显得更简单直接。
对于程序员来说,die()、reborn()的可读性更高,表达的意思明确,如老师所说,数据和表现分离,程序质量更好;
使用die()、reborn()函数,对于未来扩展程序功能来说,是保证cell与cellmashine的低耦合的良好选择。
1、降低Field和Cell的耦合度,分离二者的功能。对Cell内部的操作都交由CellMachine来完成,Field本身只负责管理Cell对象的位置,不会访问Cell内部的函数和变量。
2、便于维护和扩展。如果以后需要实现其他功能时也会用到Cell的邻居,不需要对Cell和Field做任何修改,只需要在CellMachine里修改就可以。
如果让Cell自己判断邻居情况,就需要Cell知道Field,会增加二者的耦合度;
判断属于业务逻辑的范畴,鉴于数据与表现分离的原则,Cell也不应该自己判断自己的邻居的情况来决定自己是否应该被die或reborn。
接口–狐狸与兔子
animal类
cell此时作为一个接口
//Fox extends Animal implements Cell 指FOX作为animal子类实现了Cell接口
package twenty.july.my_interface.animal;
import java.util.ArrayList;
import twenty.july.my_interface.field.Location;
public abstract class Animal {
private int ageLimit;
private int breedableAge;
private int age;
private boolean isAlive = true;
public Animal(int ageLimit, int breedableAge) {
this.ageLimit = ageLimit;
this.breedableAge = breedableAge;
}
protected int getAge() {
return age;
}
protected double getAgePercent() {
return (double) age / (double) ageLimit;
}
public abstract Animal breed();
public void grow() {
age++;
if (age >= ageLimit)
die();
}
public void die() {
isAlive = false;
}
public boolean isAlive() {
return isAlive;
}
public boolean isBreedable() {
return (age >= breedableAge);
}
public Location move(Location[] freeAdj) {
Location ret = null;
if (freeAdj.length > 0 && Math.random() < 0.02) {
ret = freeAdj[(int) (Math.random() * freeAdj.length)];
}
return ret;
}
@Override
public String toString() {
return “” + age + “:” + (isAlive ? “live” : “dead”);
}
public Animal feed(ArrayList neighbor) {
return null;
}
protected void longerLife(int inc) {
ageLimit += inc;
}
}
package twenty.july.my_interface.animal;
import java.awt.Graphics;
import twenty.july.my_interface.cell.Cell;
fox类
/
- *Fox实现接口Cell,使Fox对象能间接传给Field
*/
public class Fox extends Animal implements Cell {
public Fox() {
super(20, 4);
}
@Override // 实现接口Cell中的draw()
public void draw(Graphics g, int x, int y, int size) {
int alpha = (int) ((1 - getAgePercent()) * 255);
g.setColor(new Color(0, 0, 0, alpha));
g.fillRect(x, y, size, size);
}
@Override
public Animal breed() {
Animal ret = null;
if (isBreedable() && Math.random() < 0.05) {
ret = new Fox();
}
return ret;
}
@Override
public String toString() {
return (“Fox:” + super.toString());
}
@Override
public Animal feed(ArrayList neighbor) {
Animal ret = null;
if (Math.random() < 0.2) {
ret = neighbor.get((int) (Math.random() * neighbor.size()));
longerLife(2);
}
return ret;
}
}
rabbit类
package twenty.july.my_interface.animal;
import twenty.july.my_interface.cell.Cell;
public class Rabbit extends Animal implements Cell {
public Rabbit() {
super(10, 2); // *寿命&&生育年龄
}
@Override
public void draw(Graphics g, int x, int y, int size) {
int alpha = (int) ((1 - getAgePercent()) * 255);
g.setColor(new Color(255, 0, 0, alpha));
g.fillRect(x, y, size, size);
}
@Override
public Animal breed() {
Animal ret = null;
if (isBreedable() && Math.random() < 0.12) {
ret = new Rabbit();
}
return ret;
}
@Override
public String toString() {
return “Rabbit” + super.toString();
}
}
cell类
package twenty.july.my_interface.cell;
import java.awt.Graphics;
public interface Cell {//注意这里不能写成interface class
/
- *Cell是一个接口而非类(接口是一种完全抽象的抽象类)
- !这个接口就是为了实现Fox和Rabbit类new的对象能够传递给Field类
- Field类中指明需要的对象的类是Cell而Cell是作为中间承接者
- Fox和Rabbit类需要有implements Cell语句来实现接口
/
/* - !注意这里函数可以不用写函数前缀,只需要写返回值类型
- ?抽象类无函数主体,只需声明函数原型,实现抽象类/接口的类都必须Override所有抽象方法,否则此子类仍为抽象类
- ?abstract与final是冲突对立关系,抽象是用来被继承或重写的,final相反是不让继承/重写的
*/
void draw(Graphics g, int x, int y, int size);
}
Field类
package twenty.july.my_interface.field;
import java.util.ArrayList;
import twenty.july.my_interface.cell.Cell;
public class Field {
private int width;
private int height;
private Cell[][] field;// 声明有这么个数组变量,但未承接任何对象
private static final Location[] adjacent = {
new Location(-1, -1), new Location(-1, 0), new Location(-1, 1),
new Location(0, -1), new Location(0, 0), new Location(0, 1),
new Location(1, -1), new Location(1, 0),new Location(1, 1),
};
public Field(int width, int height) {
this.width = width;
this.height = height;
field = new Cell[height][width];
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Cell place(int row, int col, Cell o) {
// !这里的Cell o并非Cell类的对象,而是实现了Cell接口的对象(fox,rabbit)
field[row][col] = cell;
Cell ret = field[row][col];
return ret;
}
public Cell get(int row, int col) {
return field[row][col];
}
public Cell[] getNeighbor(int row, int col) {
ArrayList list = new ArrayList();
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
int r = row + i;
int c = col + j;
if (r > -1 && r < height && c > -1 && c < width && !(r == row && c == col)) {
list.add(field[r][c]);
}
}
}
return list.toArray(new Cell[list.size()]);
}
public Location[] getFreeNeighbor(int row, int col) {
ArrayList list = new ArrayList();
for (Location loc : adjacent) {
int r = row + loc.getRow();
int c = col + loc.getCol();
if (r > -1 && r < height && c > -1 && c < width && field[r][c] == null) {
list.add(new Location(r, c));
}
}
// !学着点
return list.toArray(new Location[list.size()]);
}
public boolean placeRandomAdj(int row, int col, Cell cell) {
boolean ret = false;
Location[] freeAdj = getFreeNeighbor(row, col);
if (freeAdj.length > 0) {
int idx = (int) (Math.random() * freeAdj.length);
field[freeAdj[idx].getRow()][freeAdj[idx].getCol()] = cell;
ret = true;
}
return ret;
}
public void clear() {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
field[i][j] = null;
}
}
}
public void remove(Cell fed) {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (field[row][col] == fed) {
field[row][col] = null;
break;
}
}
}
}
public Cell remove(int row, int col) { // *函数重构
field[row][col] = null;
Cell ret = field[row][col];
return ret;
}
public void move(int row, int col, Location loc) {
field[loc.getRow()][loc.getCol()] = field[row][col];
remove(row, col);
}
}
location类
package twenty.july.my_interface.field;
public class Location {
private int row;
private int col;
public Location(int row, int col) {
this.row = row;
this.col = col;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
}
view类
package twenty.july.my_interface.field;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JPanel;
import twenty.july.my_interface.cell.Cell;
public class View extends JPanel {
private static final long serialVersionUID = -L;
private static final int GRID_SIZE = 16;
private Field theField;
// *构造函数
public View(Field field) {
theField = field;
}
@Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.GRAY);
for (int row = 0; row < theField.getHeight(); row++)
g.drawLine(0, row * GRID_SIZE, theField.getWidth() * GRID_SIZE, row * GRID_SIZE);
for ( int col = 0; col<theField.getWidth(); col++ )
g.drawLine(col * GRID_SIZE, 0, col * GRID_SIZE, theField.getHeight() * GRID_SIZE);
for (int row = 0; row < theField.getHeight(); row++) {
for (int col = 0; col < theField.getWidth(); col++) {
Cell cell = theField.get(row, col);
if (cell != null)
cell.draw(g, col * GRID_SIZE, row * GRID_SIZE, GRID_SIZE);
}
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(theField.getWidth() * GRID_SIZE + 1, theField.getHeight() * GRID_SIZE + 1);
}
}
fox与rabbit类
package twenty.july.my_interface.fox_and_rabbit;
import java.util.ArrayList;
import javax.swing.JFrame;
import twenty.july.my_interface.animal.;
import twenty.july.my_interface.cell.Cell;
import twenty.july.my_interface.field.;
public class FoxAndRabbit {
private Field theField;
private View theView;
public FoxAndRabbit(int size) {
theField = new Field(size, size);
for (int row = 0; row < theField.getHeight(); row++) {
for (int col = 0; col < theField.getWidth(); col++) {
double probability = Math.random();
if (probability < 0.05) {
theField.place(row, col, new Fox());
} else if (probability < 0.15) {
theField.place(row, col, new Rabbit());
}
}
}
theView = new View(theField);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setTitle(“Cells”);
frame.add(theView);
frame.pack();
frame.setVisible(true);
}
public void start(int steps) {
for (int i = 0; i < steps; i++) {
step();
theView.repaint();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void step() {
for (int row = 0; row < theField.getHeight(); row++) {
for (int col = 0; col < theField.getWidth(); col++) {
Cell cell = (Cell) theField.get(row, col);
if (cell != null) {
Animal animal = (Animal) cell;
animal.grow();
if (animal.isAlive()) {
// *move
Location loc = animal.move(theField.getFreeNeighbor(row, col));
if (loc != null)
theField.move(row, col, loc);
// *eat
Cell[] neighbor = (Cell[]) theField.getNeighbor(row, col);
ArrayList listRabbit = new ArrayList();
for (Cell an : neighbor) {
if (an instanceof Rabbit) { // instanceof 判断是不是一个rabbit类
listRabbit.add((Rabbit) an);
}
}
if (!listRabbit.isEmpty()) {
Animal fed = animal.feed(listRabbit);
if (fed != null)
theField.remove((Cell) fed);
}
// *breed
Animal baby = animal.breed();
if (baby != null) {
theField.placeRandomAdj(row, col, (Cell) baby);
}
} else {
theField.remove(row, col);
}
}
}
}
}
public static void main(String[] args) {
FoxAndRabbit fnr = new FoxAndRabbit(50);
fnr.start(100);
}
}
不能使用animal.eat(theField),如果这么使用意味着cell知道了Field,原本是animal-Fox-rabbit是分离的,这样会使程序耦合性更紧,可扩展性变差,所以使用business-logic第三方业务逻辑程序去处理 fox得eat这个功能 。
1.Cell不知道Field:
优点:一方面,降低耦合度,保证程序的可扩展性;另一方面,遵从了数据和表现分离的原则,程序质量更佳。
缺点:Field知道Cell而Cell不知道Field的单向性,需要借助第三方平台完成业务逻辑,即进行额外的类型创建。
Cell知道Field:
优点:二者之间直接连通,不需要额外创建平台构建二者的联系。
缺点:二者的耦合度提高,关联性大,逻辑相对于不知道的情况下更复杂,不利于程序的扩展,程序的可读性也会下降,
2.要不要Animal的列表?
如果另外用一个ArrayList来表示所有的动物,每一步遍历这个列表而非整个Field,这样做是否更好?
还有个问题是遍历装着动物的容器时,对动物的操作又更新了容器,两者会有冲突,原来的代码就有这个bug:比如第1行第1列的兔子遍历时移到了第1行第2列,下个碰到的还是它……于是一轮遍历下来,有些动物会访问多次。一个解决办法是遍历容器的副本,这样每轮遍历前我们都要把Field复制一次;另外也可以让Field提供一个方法,扫描获得所有动物的列表,然后返回它来遍历。
有没有必要两种分开。比如有一个Cell抽象类表示可以放进Field的东西,另一个Drawable接口表示可以被Vier画出来的东西
异常
1-5每一个步骤都可能会出现异常,而且前一步是下一步的基础
捕获每一步可能发生的异常并处理异常
有异常抛出如果所处是函数则下一步到该函数调用者,如果所处代码块不是函数或是try但不与catch匹配都退出到外层在进行判断是否是try是否是函数返回调用者
e.getMessage()代表使用捕获到的异常e的getMessage()方法获得到的 异常 的信息为10证(数组索引为10处超过边界)
直接println(e)输出10,main(报错的代码块是main)说明异常已经封装了String toString函数了
e.printStackTrace后台打印出报的异常的路径
在catch中对异常进行处理后,throw e;相当于再将异常抛出
class OpenException extends Throwable{} //构造新的异常时需要创建新的异常类,让其继承自Throwable变成可抛出的异常
class CloseException extends Throwable{} //所有的系统的异常都是继承自Exception的,而Throwable是继承自Exception的
public class ArrayIndex {
public static int open() {
return -1;
}
public static void readFile() throws OpenException,CloseException
{ //如果调用一个可能会抛出异常的函数则必须:
try { //1.在封装读入文件函数中抛出异常功能时要么在函数后声明throws OpenException,CloseException
//并在测试用例中在调用readFile时加入try-Catch块捕捉异常进行处理
//2.要么在readFile函数中的throw new OpenException();代码块的外部加入try-Catch块捕捉异常进行处理
if(open()==-1)
{
throw new OpenException();
}
}catch(OpenException e)
{
e.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
readFile();
} catch (OpenException | CloseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (NullPointerException e)
{
e.printStackTrace();
}
}
}
这段代码前面 closeException继承自openException,openException继承自Exception,后面测试用例处会先被catch(closeException)捕获子类异常的代码捕捉到,就轮不到后面捕获父类openException的代码就终止了。
而如果将子类的catch放在父类的catch后面,则会优先被捕捉父类异常的代码捕捉,子类catch处报错.。。
catch(Exception e)能捕捉任何异常,如果前面的程序把catch(OpenException e)放在前面,catch(Exception e)放在后面,则程序不会报错,因为OpenException是Exception的子类。
【如果在main最后加入catch(Exception e)捕捉所有异常】在出现索引超出数组维度(运行时刻异常)后,程序还没有运行到openException就直接进入try-catch代码块,并报出运行时刻异常时的错误。
当异常遇上继承
class OpenException extends Exception{} //作为子类的成员函数不能增加比父类更多的异常
class CloseException extends OpenException{} //作为子类的构造函数可以增加比父类更多的异常
class NewException extends Exception{}
public class Exception2 {
public Exception2() throws OpenException{} //当父类的构造函数声明了异常时
public void f() throws OpenException{}
}
class Exception3 extends Exception2
{
public void f() throws OpenException{}
//public void f() throws OpenException,NewException{} 注意这里不可以throws父类没有的异常
//因为如果throws父类没有的异常,后面的向上造型是将 Exception3(子类)当成Exception2(父类)的父类中没有声明的异常子类中也不应该声明包含
public Exception3() throws OpenException,NewException{}
//当父类的构造函数声明了异常时,子类也都得声明了这些异常,并且还可以添加自己的异常
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Exception2 e = new Exception3(); //向上造型
e.f();
} catch (OpenException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
流
inputStream与outputStream读的是字节
mark与reset代表读一个流做标记与返回标记处
available代表着是还有多少字节可以读
对于国标码来说汉字两个字占4个字节
对于utcode来说汉字占据两个字符
flush作用是清空缓冲区
FileReader是InputStreamReader(将输入Stream转化为Reader)的一个子类,FileReader可以在一个二进制非unicode文件建立起一个流,如何只有裸的操作文件才用FileReader,且不能做文字的编码处理
BufferedReader类中的readline()方法读入文本文件中一整行
可实现在行之间跳转,可以使用让他跳转到第几行
汉字编码
格式化输入输出
printf方法与C语言中相同
如果文件是一个二进制的就用InputStream来读,可读入成基本数据类型就用DataInputStream,若文件中表达的是文本,想要读成一整段的文字就用reader来读,想把一段文字解析成各种基本数据类型格式化就用Scanner。
流的应用
对象串行化
File类
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/25260.html