基本知识
引用和对象
- 新建一个对象
class Tank {
int level;
}
public class Assignment {
public static void main(String[] args) {
Tank t1=new Tank();
Tank t2=new Tank();
t1.level=9;
t2.level=47;
}
}
- 引用在赋值,对象不赋值
t1=t2;
//此时t1.level=t2.level=47
t1.level=27;
//此时t1.level=t2.level=27
//因为t1和t2都是同一个对象的引用了
基本数据类型
- 其它数据类型不能自动转换为boolean
int a=1;
if(a) { //illegal!
}
enum
public enum VIPClass {
BRONZE,SILVER,GOLD,DIAMOND;
}
private VIPClass vipClass=VIPClass.DIAMOND;
String
int length(); //返回字符串长度
char charAt(int i); //返回索引位置的字符
char[] getChars(int start,int end);
byte[] getBytes(int start,int end);
boolean equals(String s); //字符串的比较不能用==
int indexOf(char c); //返回c在字符串中的位置,如果没有返回-1
String subString(int start,int end); //获取字串(不包含end)
初始化
基本数据类型初始化
- 如果没有赋初值,Java会自动为其赋为默认值,如整型为0
构造器初始化
- 每个类有一个默认的无参构造器,但如果声明了有参的构造器,Java不会帮你再生成默认的无参构造器
静态数据的初始化
static String str1="hello";
static String str2;
static{
str2="world";
}
数组的初始化
String[] s1=new String[10];
String[] s2=new String[] {};
String[] s3=new String[] {"hello","world"};
String[] s4=new String[] {new String("hello"),new String("world")};
控制执行流程
-
for-each语法
import java.util.*;
Random rand=new Randon(47);
//47是种子,种子一样,生成的随机数也一样
//无参会使用系统当前的时间作为种子
int r[]=new int[10];
for(int i=0;i<10;i++) {
r[]=rand.nextInt(26); //生成0-26之间(不含26)的随机整数
}
//不需要知道x是r数组中的第几个时,可以用for-each语法
for(int x:r) {
System.out.println(x);
}
- 输出指定个数的斐波那契数列
int fibonacci(int n) {
if(n==1||n==2)
return 1;
else
return fibonacci(n-1)+fibonacci(n-2); //递归
}
for(int i=1;i<=n;i++) //n是指定个数
System.out.print(fibonacci(i)+" ");
- 输出4位数的吸血鬼数字
int vam[]=new int[4]; //存储四位数
boolean vampire(int m,double a,double b,int i,int j) { //判断是否为吸血鬼数字
int k=(int)b%10;
int l=(int)b/10;
for(int p=0;p<4;p++) {
if(vam[p]==k&&p!=i&&p!=j)
for(int q=0;q<4;q++)
if(vam[q]==l&&q!=i&&q!=j&&q!=p) {
System.out.println(m+"="+(int)a+"*"+(int)b);
return true;
}
}
return false;
}
double a,b;
for(int m=1001;m<10000;m++) { //遍历所有四位数
boolean isVamp=false;
if(m%100==0) //100的整数倍肯定不是
continue; //Java不允许if里什么也不写
int m2=m;
for(int i=0;i<4;i++) { //将四位数每一位拆开
vam[i]=m2%10;
m2=m2/10;
}
for(int i=0;i<4;i++) { //随机组合
for(int j=i+1;j<4;j++) {
if(j==i)
continue;
if(vam[j]!=0) {
a=vam[i]+vam[j]*10;
b=m/a;
if((int)b==b) {
isVamp=vampire(m,a,b,i,j);
if(isVamp)
break;
}
}
if(vam[i]!=0) {
a=vam[j]+vam[i]*10;
b=m/a;
if((int)b==b) {
isVamp=vampire(m,a,b,i,j);
if(isVamp)
break;
}
}
if(isVamp)
break;
}
if(isVamp)
break;
}
}
封装性
访问权限
private | friendly | protected | public | |
同一类 | √ | √ | √ | √ |
同一文件 | √ | √ | √ | |
同一文件夹 | √ | √ | √ | |
其他子类 | √ | √ | ||
其它类 | √ |
单例模式
private static View instance; //只有一个实例化对象
public static View getInstance() {
if (instance==null) {
instance = new View();
} //第一次调用时才创建
return instance;
}
继承性
继承与组合
- 组合:在类里直接声明某个类的对象 ➡️更看重功能
- 继承:继承自父类 ➡️更看重接口,可以重载父类的方法
继承与重载
class Cleanser{
private String s="Cleanser";
public void append(String a) {
s+=a;
}
public void scrub() {
append(" scrub");
}
public void dilute() {
append(" dilute");
}
@Override
public String toString() { //重载object函数
return s;
}
public static void main(String[] args) {
Cleanser c=new Cleanser();
c.scrub();
System.out.println(c);
}
}
class Detergent extends Cleanser{
@Override
public void scrub() { //覆盖父类函数
append(" Detergent.scrub()");
super.scrub(); //调用父类函数
}
public static void main(String[] args) {
//在public类以外的类也可以有main函数,但如果不在public类的main函数中调用就不会运行
Detergent d=new Detergent();
d.scrub();
d.dilute();
System.out.println(d);
System.out.println("Testing base class:"); //测试父类
Cleanser.main(args); //调用其他类里的main函数
}
}
public class Sterilizer extends Detergent{
@Override
public void scrub() { //覆盖父类
append(" Sterilizer.scrub()");
super.scrub(); //调用父类函数
}
public void sterilize() { //增加新的函数
append(" Sterilizer.sterilize()");
}
public static void main(String[] args) {
Sterilizer s=new Sterilizer();
s.scrub();
s.sterilize();
System.out.println(s);
System.out.println("Testing base class:"); //测试父类
Detergent.main(args); //调用其他类里的main函数
}
}
初始化
- 如果父类有有参构造器,在子类的构造函数中需要初始化父类
class Code{
private int co;
Code(int i){
System.out.println("Code constructor "+i);
co=i;
}
protected void showCode() {
System.out.println("The code is "+co);
}
}
class Encrypting extends Code{
Key k=new Key(1);
Encrypting(){
super(1); //父类有有参构造函数,这里必须要初始化父类
System.out.println("Encrypting constructor ");
}
Encrypting(int i){
super(i);
System.out.println("Encrypting constructor "+i);
}
void printCode() {
showCode();
}
}
初始化顺序
- 静态初始化
- 动态初始化
- 构造器初始化
class Insect{
private int i=9;
protected int j;
Insect(){
System.out.println("Insect constructor");
System.out.println("i="+i+",j="+j);
j=39;
}
}
class Beetle extends Insect{
private int k=47;
Beetle(){
System.out.println("Beetle constructor");
System.out.println("j="+j+",k="+k);
}
}
public class Crustacea extends Beetle{
private int l=23;
Crustacea(){
System.out.println("Crustacea constructor");
System.out.println("l="+l);
}
public static void main(String[] args) {
Crustacea c=new Crustacea();
}
}
/*
Insect constructor
i=9,j=0
Beetle constructor
j=39,k=47
Crustacea constructor
l=23
*/
代理
- 暴露类中的全部或部分方法
//使用代理的方法
public class Sterilizer{
//要定义成员,因为没有继承到父类的s
private String s="Sterilizer";
@Override
public String toString() { //重载object函数
return s;
}
private Detergent d=new Detergent(); //代理
public void scrub() {
d.scrub();
System.out.println(d);
}
public static void main(String[] args) {
Sterilizer s=new Sterilizer();
s.scrub();
// s.dilute(); 非法,因为通过代理方式,没有暴露出Detergent中的这个函数
System.out.println(s);
System.out.println("Testing base class:"); //测试父类
Detergent.main(args); //调用其他类里的main函数
}
}
finally关键字
- 无论发生什么事,都要执行finally中的代码
//请以此例再次熟悉初始化顺序
class Component1{
Component1(){
System.out.println("Component1 constructor");
}
void dispose() {
System.out.println("Erasing Component1");
}
}
class Component2{
Component2(){
System.out.println("Component2 constructor");
}
void dispose() {
System.out.println("Erasing Component2");
}
}
class Component3{
Component3(){
System.out.println("Component3 constructor");
}
void dispose() {
System.out.println("Erasing Component3");
}
}
class Root{
Component1 c1=new Component1();
Component2 c2=new Component2();
Component3 c3=new Component3();
Root(){
System.out.println("Root constructor");
}
void dispose() {
System.out.println("Erasing Root");
}
}
public class Stem extends Root{
Stem(){
System.out.println("Stem constructor");
}
void dispose() {
System.out.println("Erasing Stem");
super.dispose();
}
Component1 c1=new Component1();
Component2 c2=new Component2();
Component3 c3=new Component3();
public static void main(String[] args) {
Stem s=new Stem();
try {
System.out.println("Trying method");
} finally {
s.dispose();
}
}
}
/*
//先初始化root的成员
Component1 constructor
Component2 constructor
Component3 constructor
Root constructor
//先初始化stem的成员
Component1 constructor
Component2 constructor
Component3 constructor
Stem constructor
Trying method
//垃圾回收
Erasing Stem
Erasing Root
*/
向上转型
- 子类对象充当父类的引用
public static void tuneAll(Instrument[] e) {
for(Instrument i:e) //for each
tune(i);
}
public static void main(String[] args) {
Instrument[] orchestra= { //父类引用=子类对象
new Wind(),
new Percussion(),
new Stringed(),
new Brass(),
new WoodWind(),
new Piano()
};
tuneAll(orchestra); //向上转型
for(Instrument o:orchestra)
System.out.println(o);
}
多态性:接口
抽象类
- 没有方法体
- 不能声明具体对象
- 如果子类还没有声明具体实现,那还是抽象类
abstract class Test{
Test(){
print();
}
public abstract void print();
}
class ExportTest extends Test{
private int i=1;
ExportTest(){
System.out.println("ExportTest constructor");
}
public void print() {
System.out.println(i);
}
}
public class Excercise9 {
public static void main(String[] args) {
// Test t=new Test(); illegal!
ExportTest et=new ExportTest();
et.print();
//先调用基类的构造器,但基类的print是抽象方法,转而调用导出类的print
}
}
接口
- 变量自动是static&final
- 方法自动是public,都没有具体实现
- 不能声明具体对象,但可以声明引用
nterface Playable{
void play(Note n);
}
interface Instrument{
int VALUE=5; //static&final;
//cannot have method definitions:
void adjust(); //automatically public
}
class Wind implements Instrument,Playable{
public void play(Note n) {
System.out.println(this+".play() "+n);
}
@Override
public String toString(){
return "Wind";
}
public void adjust() {
System.out.println(this+".adjust()");
}
}
public class Music {
static void tune(Playable p) {
p.play(Note.MIDDLE_C);
}
static void tuneAll(Playable[] e) {
for(Playable i:e)
tune(i);
}
public static void main(String[] args) {
Playable[] orchestra= { //可以声明接口的引用
new Wind(),
new Percussion(),
new Stringed(),
new Brass(),
new Woodwind()
};
tuneAll(orchestra);
}
}
适配器
- 实现接口需要实现接口中所有的方法
- 使用适配器可以只重载部分方法
多重继承
- 可以继承任意多个接口
- 接口之间也可以任意继承
接口与工厂
- 可以将某个实现替换为另一个实现(类似模版)
- 利用工厂实现抛硬币和掷骰子的功能
interface Play {
void game();
}
interface PlayFactory {
Play getPlay();
}
class FlipTheCoin implements Play {
@Override
public void game() {
System.out.println("Flip a coin!");
for(int i=1;i<=10;i++)
flip();
}
public void flip() {
Random rand=new Random();
switch(rand.nextInt(2)) {
case 0:
System.out.println("Upper side!");
break;
case 1:
System.out.println("Down side!");
break;
}
}
}
class RollTheDice implements Play {
@Override
public void game() {
System.out.println("Roll a dice!");
for(int i=1;i<=10;i++)
roll();
}
public void roll() {
Random rand=new Random();
System.out.println(rand.nextInt(6)+1);
}
}
class CoinFactory implements PlayFactory {
@Override
public Play getPlay() {
return new FlipTheCoin();
}
}
class DiceFactory implements PlayFactory {
@Override
public Play getPlay() {
return new RollTheDice();
}
}
public class Games {
public static void gamePlayer(PlayFactory fact) {
Play p=fact.getPlay();
p.game();
}
public static void main(String[] args) {
gamePlayer(new CoinFactory());
gamePlayer(new DiceFactory());
}
}
内部类
- 定义在另一个类中的类,叫做内部类
- 内部类可以访问外部类的所有
创建和访问内部类
public class Outer {
class Inner {}
public Inner getInner(){ //动态方法中可以随便构造内部类对象
return new Inner();
}
public static void main(String[] args) { //静态方法中构造内部类对象
Outer o=new Outer(); //必须先构造外部类对象
Outer.Inner i1=o.getInner(); //调用类内的动态方法
Outer.Inner i2=o.new Inner(); //直接创建
}
}
匿名内部类
public interface Inner { //接口
int value();
}
public class Outer {
public Inner inner() { //创建一个实现Inner的匿名类的对象
return new Inner() {
public int value(){}
}
}
public static void main(String[] args) {
Outer o=new Outer();
Inner i=o.inner();
}
}
容器
Collection
List
- 可以自动扩容
- ArrayList: 数组,便于随机访问元素,但插入和删除较慢
- LinkedList: 链表,便于插入和删除,但随机访问较慢
class ListFeatures {
public static void main(String[] args) {
Random rand=new Random(47);
List<Integer> ints=new ArrayList<Integer>(7);
for(int i=10;i<17;i++)
ints.add(i);
System.out.println("1: "+ints);
ints.add(7); //自动扩容
System.out.println("2: "+ints);
System.out.println("3: "+ints.contains(7)); //是否包含某个数据
ints.remove(7); //删除数据
int t=ints.get(2); //获取列表中的下标为2的数据
System.out.println("4: "+t+" "+ints.indexOf(t)); //返回某个数据在列表中的下标
System.out.println("5: "+ints.remove(2)); //删除链表中下标为2的数据
System.out.println("6: "+ints);
ints.add(3,9); //在下标为3的位置插入元素9
System.out.println("7: "+ints);
List<Integer> sub=ints.subList(1, 4); //获取下标为1-4的数据形成子列(不含4)
System.out.println("8: Sublist: "+sub);
System.out.println("9: "+ints.containsAll(sub)); //返回是否包含子列中的所有元素
Collections.sort(sub); //按照升序整理子列
System.out.println("10: Sorted sub: "+sub);
System.out.println("11: "+ints.containsAll(sub)); //该函数与顺序无关
Collections.shuffle(sub,rand); //随机排列列表
System.out.println("12: Suffled sub: "+sub);
System.out.println("13: "+ints.containsAll(sub));
List<Integer> copy=new ArrayList<Integer> (ints); //生成副本
sub=Arrays.asList(ints.get(1),ints.get(4)); //获取下标为1、4的数据生成列表
System.out.println("14: Sub: "+sub);
copy.retainAll(sub); //取交集
System.out.println("15: Copy: "+copy);
copy=new ArrayList<Integer> (ints); //重新生成副本
copy.remove(2);
System.out.println("16: "+copy);
copy.removeAll(sub); //删除包含子列的数据
System.out.println("17: "+copy);
copy.set(1, 23); //将下标为1的数据设置成23
System.out.println("18: "+copy);
copy.addAll(2,sub); //从下标为2的数据开始,插入子列
System.out.println("19: "+copy);
System.out.println("20: "+ints.isEmpty()); //返回列表是否为空
ints.clear(); //清除所有数据
System.out.println("21: "+ints);
System.out.println("22: "+ints.isEmpty());
ints.addAll(sub); //将子列中所有数据加入
System.out.println("23: "+ints);
}
}
Stack
//+压栈,-弹出
String s="+U+n+c---+e+r+t---+a-+i-+n+t+y---+-+r+u--+l+e+s---";
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
if(s.charAt(i)=='+')
stack.push(s.charAt(++i));
else
System.out.print(stack.pop()+" ");
}
Set
不存在重复的对象
//统计输入的元音字母的总和
public class UniqueWords {
public static void main(String[] args) {
Set<Character> unique=new HashSet<Character>();
unique.add('a');
unique.add('e');
unique.add('i');
unique.add('o');
unique.add('u');
unique.add('A');
unique.add('E');
unique.add('I');
unique.add('O');
unique.add('U');
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
String s=null;
try {
System.out.println("Please input a sentence!");
s=in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
int count=0;
for(int i=0;i<s.length();i++) {
Iterator<Character> it=unique.iterator(); //注意迭代器的声明要放在这里,才可以每次都重新指向第一个
for(int j=0;j<unique.size();j++) {
if(s.charAt(i)==it.next()) //通过迭代器获取HashSet中的元素
count++;
}
}
System.out.println("There are "+count+" unique words in this sentence.");
}
}
Queue
Random rand=new Random();
PriorityQueue<Double> pq=new PriorityQueue<>();
for(int i=0;i<10;i++)
pq.offer(rand.nextDouble());
System.out.println(pq);
for(int i=0;i<10;i++)
pq.poll();
System.out.println(pq);
Iterator
单向移动
class RandomRodentGenerator { //啮齿类动物生成器
private Random rand=new Random(); //随机数
public Rodent next() {
switch(rand.nextInt(3)) {
default:
case 0:
return new Mouse();
case 1:
return new Gerbil();
case 2:
return new Hamster();
}
}
}
ArrayList<Rodent> rodents=new ArrayList<Rodent>();
for(int i=0;i<9;i++)
rodents.add(gen.next());
Iterator<Rodent> it=rodents.iterator(); //迭代器
while(it.hasNext()) { //序列中还有下一个
Rodent ro=it.next(); //获取下一个元素
ro.bite();
//迭代器自动向前移动一个位置
}
ListIterator
双向移动
//把序列1的元素反序插入序列2
List<Integer> i1=new ArrayList<Integer>(8);
for(int i=0;i<8;i++)
i1.add(i);
List<Integer> i2=new ArrayList<Integer>(8);
ListIterator<Integer> it=i1.listIterator(8); //从最后一个位置开始
while(it.hasPrevious()) { //如果有前一个元素
Integer i=it.previous();
i2.add(i);
}
Map
- 储存健值对 key&value,类似关联数组
ArrayList<Gerbil> gerbils=new ArrayList<>();
for(int i=1;i<=3;i++)
gerbils.add(new Gerbil(i));
Map<String,Gerbil> m=new HashMap<>();
String[] str= {"Catherine", "Ann", "Elizabeth"};
for(int i=0;i<3;i++)
m.put(str[i], gerbils.get(i)); //将元素放入Map
System.out.println(m);
Set<String> set=m.keySet(); //获取Set的key
Iterator<String> it2=set.iterator(); //创建迭代器
while(it2.hasNext()) {
String key=it2.next();
System.out.println(m.get(key)); //通过key找到Map中的元素
m.get(key).hop();
}
I/O流
File
new File(String path); //创建一个文件对象
boolean exist(); //是否存在
boolean isFile(); //是文件吗
boolean isDirectory(); //是文件夹吗
String getName(); //获取文件名
String getPath(); //获取文件路径
long length(); //文件长度
boolean canRead(); //可读吗
boolean canWrite(); //可写吗
String[] list(); //目录中的文件
boolean renameTo(File newFile); //相当于新建一个文件
boolean delete(); //删除文件
boolean mkdir(); //在当前位置创建一个文件夹
boolean mkdirs(); //在当前位置创建多层文件夹
public class Excercise18 {
static int countDir=0,countFile=0;
static double size=0;
public static void main(String[] args) {
File f=new File("/Users");
getFile(f);
System.out.println("There are "+countDir+" directories."); //输出文件夹数目
System.out.println("There are "+countFile+" files."); //输出文件总数
getSize(); //输出文件尺寸大小
}
public static void getFile(File f) { //递归函数
if(f.isFile()) { //如果是文件
countFile++;
size+=f.length();
}
if(f.isDirectory()) { //如果是文件夹
countDir++;
File[] files=f.listFiles(); //获取文件夹下的所有文件或文件夹
for(File temp:files) { //遍历,递归
getFile(temp);
}
}
}
public static void getSize() { //把计算出来的尺寸(B)转化为合适的单位
String[] s=new String[]{"B","KB","MB","GB"};
int mark=0;
while(size>1024&&mark<4) { //选取合适的单位,最大单位到GB
size/=1024;
mark++;
}
DecimalFormat df=new DecimalFormat("#.00"); //保留两位小数
System.out.println("The total size is "+df.format(size)+s[mark]);
}
}
FilenameFilter
class DirFilter implements FilenameFilter {
public boolean accept(File dir) {
...
if(name.endsWith(".pdf")))
return true;
else
return false;
}
}
输入输出
读入文件
public static String read(String name) throws IOException {
BufferedReader in=new BufferedReader(new FileReader(name));
String s;
StringBuilder sb=new StringBuilder();
while((s=in.readLine())!=null) {
sb.append(s+"\n");
}
in.close();
return sb.toString();
}
public static void main(String[] args) throws IOException {
System.out.println(read("file path"));
}
写入文件
public static void main(String[] args) throws IOException {
BufferedReader in=new BufferedReader(new StringReader(Excercise18.read("file path"))); //刚刚写的read函数
PrintWriter out=new PrintWriter("Excercise18.out");
int lineCount=1; //记录行数
String s;
while((s=in.readLine())!=null) {
out.println(lineCount++ +":"+s);
}
out.close();
System.out.println(Excercise18.read("Excercise18.out")); //在命令行输出
FileOutputStream fos = new FileOutputStream("new file path"); //新建文件
byte[] content=read("file path").getBytes(); //把要写入的内容转化为byte
fos.write(content); //写入
fos.close();
//从doc这类文件读和写的时候,中文都会变成乱码(因为Java一处编写、处处运行的特点)
}
从命令行中读取
//从命令行获取输入
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
try {
String line;
line=in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
多线程
建立线程
实现Runnable接口
public class LiftOff implements Runnable {
public void run() {
while(true) {
......
}
}
Thread t=new Thread(new LiftOff());
t.start();
}
继承Thread类
class SimpleThread extends Thread {
public void run() {
while(true) {
......
}
}
}
new SimpleThread().start();
//匿名内部类的形式
public class Test {
new Thread() {
public void run() {
while(true) {
......
}
}
}.start();
}
使用Executor(线程池)
public class CachedThreadPool {
public static void main(String[] args) {
ExecutorService exec=Executors.newCachedThreadPool(); //创建线程池
for(int i=0;i<5;i++){ //给每个任务分配一个线程
exec.execute(new LiftOff()); //Runnable的实现类
}
exec.shutdown();
}
}
//可以自动扩容的线程池
ExecutorService exec1=Executors.newCachedThreadPool();
//指定数量的线程池,如果线程超过5,后面的任务需要等待
ExecutorService exec2=Executors.newFixedThreadPool(5);
//单线程
ExecutorService exec3=Executors.newSingleThreadPool();
从任务中返回值
class TaskWithResult implements Callable<String> { //实现一个泛型接口
private int id;
public TastWithResult(int id) {
this.id=id;
}
public String call() {
return "result of TaskWithResult"+id;
}
}
public class CallableDemo {
public static void main(String[] args) {
ExecutorService exec=Executors.newCachedThreadPool();
ArrayList<String> results=new ArrayList<>;
for(int i=0;i<10;i++) {
results.add(exec.submit(new TaskWithResult(i)));
}
for(String s:results) {
try {
System.out.println(s.get()); //这时线程可能还没执行完
} catch(Exception e) {
System.out.println(e);
} finally {
exec.shutdown();
}
}
}
}
加入一个线程
等到Sleeper线程结束,Joiner线程才会继续进行
class Sleeper extends Thread {
public void run() {
sleep(1000); //休眠,以毫秒为单位
}
}
class Joiner extends Thread {
Sleeper s;
Joiner (Sleeper s) {
this.s=s;
}
public void run() {
s.join();
System.out.println("wake up");
}
}
锁
多线程可以共用一把锁,当有线程要执行时,它获取锁,并且上锁,其他线程要执行时,看到上锁了,就挂起,等待上锁的线程使用完毕释放锁,其他的线程才能继续进行。
class Meal {
......
}
class Waiter implements Runnable {
private Restaurant r;
public Waiter(Restaurant r) {
this.r=r;
}
public void run() {
try {
while(!Thread.interrupted() {
synchronized(this) {
while(r.meal==null)
wait();
}
}
} catch(InterruptedException e){
System.out.println("Waiter interrupted");
}
synchronized(r.chef) {
r.meal=null;
r.chef.notifyAll();
}
}
}