使用面向对象的思路介绍Java的基础知识,从对象的基本概念、变量、方法,到函数库,集成与多态,静态,再到GUI,序列化,网络,数据结构,最后介绍发布和远程调用。html
本书最大的启发是创建面向对象的基本思想,万物皆在对象中,究竟是如何组成和实现的。java
最经常使用的java数据库
public class ClassName { public static void main(String[] args){ System.out.println("Hello World!"); } }
(int)(Math.random()*length)
来出现随机数;api
public static final double PI=3.1415
public表示可供各方读取,static表示不用建立实例便可使用,final表示不变;静态final变量默认取名大写,且必须初始化。java.util.Calendar对象来操做日期数组
Calendar cal = Calendar.getInstance(); cal.set(2017,1,6,15,40); cal.getTimeInMillis(); cal.HOUR_OF_DAY cal.add(cal.DATE, 30);//月份滚动 cal.roll(cal.DATE, 30);//月份不动 cal.set(cal.DATE, 1); //重要的方法 add(int field, int amount) get(int field) getInstance() getTimeInMillis() roll(int field, int amount) set(int field, int amount) set(year,month,day,hour,minute) setTimeInMillis(long millis) //关键字段 DATE / DAY_OF_MONTH HOUR / HOUR_OF_DAY MILLISECOND MINUTE MONTH YEAR ZONE_OFFSET
import static java.lang.System.out;静态的import能够到方法,而后直接调用out便可,不建议使用;浏览器
会抛出异常的方法必需要声明它有可能会这么作。方法能够抓住其余异常,异常总会丢回给调用方;安全
public void takeRisk() throws BadException{ if (abandonAllHope){ throw new BadException(); } } public void crossFingers(){ try{ anObject.takeRisk(); }catch (BadException ex){ System.out.println("Aaargh"); ex.printStackTrace(); } }
throws Exception1, Exception2
;catch也能够用相似switch语句同样来分别处理,可是要从小到大;duck异常表示,当调用有异常的方法,也声明会抛出异常时,能够不把此方法的调用放在try/catch块中,可是不推荐这么作。服务器
监听和事件源之间的沟统统过程序代码调用button.addActionListener(this)
来向按钮注册。按钮会在事件发生时,调用注册该接口的方法actionPerformed(theEvent)
;网络
import javax.swing.*; import java.awt.event.*; public class SimpleGui1B implements ActionListener{ JButton button; public static void main(String[] args){ SimpleGui1B gui = new SimpleGui1B(); gui.go(); } public void go(){ JFrame frame = new JFrame(); button = new JButton("click me"); button.addAcitonListener(this); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(button); frame.setSize(300,300); frame.setVisible(true); } public void actionPerformed(ActionEvent event){ button.setText("I've been clicked!"); } }
当有多个widget须要监听事件时,用内部类来解决;数据结构
public void go(){ //... labelButton.addActionListener(new LaberlListener()); colorButton.addActionListener(new ColorListener()); label = new JLabel("I'm a label") //... } class LaberListener implements ActionListener { public void actionPerformed(ActionEvent event){ labnel.setText("Ouch!") } }
每一个背景组件均可以有自定义规则的布局管理器。BorderLayout表示五个区域,是frame默认的,FlowLayout表示从左至右,有必要时换行,是panel默认的;BoxLayout以垂直排列;
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.add(button); frame.getContentPane().add(BorderLayout.North, panel);
JTextField文本框组件,JTextArea可滚动的文本框组件,JCheckBox组件,JList组件均为经常使用组件。
序列化写入的步骤:建立FileOutputStream对应一个文件xxx.ser,有FileStream建立ObjectOutputStream,由ObjectOutputStream写入object,关闭ObjectOutputStream。其中须要注意,可以写入ObjectOutputStream的object必须implements Serializable,可是不须要实现任何方法。
FileOutputStream fileStream = new FileOutputStream("MyGame.ser"); ObjectOutputStream os = new ObjectOutputStream(fileStream); os.writeObject(characterOne); os.close();
transient String currentID;
解序列化步骤,建立FileInputStream读取一个文件,建立ObjectInputStream,读取对象,转换对象类型,关闭。
FileInputStream fileStream = new FileInputStream("MyGame.ser"); ObjectInputStream os = new ObjectInputStream(fileStream); Object one = os.readObject(); GameCharacter elf = (GameCharacter) one; os.close()
读写文本文件。注意可使用缓冲区的方法来减小磁盘IO。使用writer.flush()强制缓冲区内容写入磁盘。
import java.io.*; class WriteAFile{ public static void main(String[] args){ try { FileWriter writer = new FileWriter("Foo.txt"); writer.write("hello, foo!"); //BufferedWriter bWriter = new BufferedWriter(writer); //bWriter.flush(); writer.close(); File myFile = new File("Foo.txt"); FileReader fileReader = new FileReader(myFile); BufferedReader reader = new BufferedReader(fileReader); String line = null; while((line = reader.readLine()) != null){ System.out.println(line); } reader.close(); } catch(IOException ex){ ex.printStackTrace(); } } }
java.io.File类的操做
//建立出File对象 File f = new File("MyCode.txt"); //建目录 File dir = new File("Chapter_8"); dir.mkdir() //列出目录内容 if (dir.isDirectory()){ String[] dirContents = dit.list(); } //取得绝对路径 dit.getAbsolutePath(); //删除文件 boolean isDeleted = f.delete()
每一个对象被序列化的同时,都会带上一个类的版本的识别ID,即serialVersionUID。所以要注意版本。
网络接收消息的步骤:创建socket链接,输入到底层的InputStreamReader上,转换到缓冲区字符BufferedReader,读取数据;
Socket chatSocket = new Socket("127.0.0.1", 5000); InputStreamReader stream = new InputStreamReader(chatSocket.getInputStream()); BufferedReader reader = new BufferedReader(stream); String message = reader.readline(); reader.close();
写消息的流程是:创建socket,getOutputSream并创建PrintWriter,写入数据;
Socket chatSocket = new Socket("127.0.0.1", 5000); PrintWriter writer = new PringWriter(chatSocket.getOutputStream()); writer.println("haha"); writer.close();
服务器端创建服务的流程为:创建ServerSocket,等待客户端链接,客户链接后,调用accept方法创建新的socket。
ServerSocket serverSock = new ServerSocket(5000); while(true){ Socket sock = serverSock.accept(); PrintWriter writer = new PrintWriter(sock.getOutputStream()); writer.println("haha"); writer.close(); }
Runnable是一个接口,它只有一个方法public void run()。它就是线程要执行的工做。
public class MyRunnable implements Runnable { public void run(){ go(); } public void go(){ System.out.println("top o' the stack"); } } class ThreadTestDrive{ public static void main(String[] args){ Runnable threadJob = new MyRunnable(); Thread myThread = new Thread(threadJob); myThread.start(); System.out.println("back in main"); } }
线程会产生并发性问题(concurrency),并发性问题会引起竞争状态(race condition),竞争状态会引起数据损毁。举个例子,两个线程共用一个余额,每次用钱时,先检查余额,再扣钱。这样会因为竞争缘由出现负数。因此须要一把锁,来保证一个方法一次只能被一个线程调用,即用synchronized关键字。
private synchronized void makeWithDrawa(int amount){ //... }
同步化能够只修饰几行,这样能够减少原子操做的范围,提升效率。
private void makeWithDrawa(int amount){ //... synchronized(this){ //... } }
静态的方法是运行在类上的,当要对静态的方法作同步化是,会使用类自己的锁。
泛型有三件事是重要的:
new ArrayList<Song>(); //建立实例 ArrayList<Song> songList = new ArrayList<song>(); //声明指定泛型类型的变量 void foo(ArrayList<Song> list); //声明或调用指定泛型的方法
在说明文件中,通常用E表示指定类型;
public class ArrayList<E> extends AbstractList<E> implements List<E> ...{ public boolean add(E o) }
运用泛型的方法可使用未定义在类声明的类型参数。
public <T extends Animal> void takeThing(ArrayList<T> list) //与后续的万用字符相同 public void takeThing(ArrayList<? extends Animal>) //与下面不同,下面的只能使用Animal,不能使用其子类 public void takeThing(ArrayList<Animal> list)
一样若是要使用HashSet去除重复,针对自定义类,要覆盖equals方法和hashCode方法。它的比较过程是先比较hashCode(),若是相同,再比较equals。
class Song implements Comparable<Song>{ ... public boolean equals(Object aSong){ Song s = (Song)aSong; return getTitle().equals(s.getTitle()); } public int hashCode(){ return title.hashCode(); } }
HashMap适合用KV场景存储数据
HashMap<String, Integer> scores = new HashMap<String, Integer>(); scores.put("Bert", 43); System.out.println(scores.get("Bert"));
泛型参数和数组参数的区别
public void takeAnimals1(ArrayList<Animal> animals) public void takeAnimals2(Animal[] animals) //takeAnimals1(new ArrayList<Dog> dogs)会出错,编译错误 //takeAnimals2(new Dog[] dogs)不会出错 //前者能够防止在函数中进行Dog的特有相关操做,后者在执行期若是运行相关操做,会抛出异常
为了解决上述前者的问题,可使用万用字符
public void takeAnimals3(ArrayList<? extends Animal> animals) //为了防止此时,将ArrayList<Dog>中加入Cat,当用万用字符时,不能对队列作加入操做
可使用-d class_path
来将源代码与类文件相分离,实现对源码的保护;
javac -d ../classes *.java
jar相似tar命令,它有本身的规则。首先要肯定全部的类文件都在classes目录下,其次要有manifest.txt文件来描述哪一个类带有main()方法,最后执行命令打jar包
cat manifest.txt Main-Class:MyApp cd MiniProject/classes jar -cvmf manifest.txt app1.jar *.class
java -jar app1.jar
。而为了防止包命名冲突,通常反向使用domain做为包名称。
com.headfirstbooks.Book com.headfirstjava.projects.Chart
package com.headfirstjava;
。而后要设定对应的目录结构。Main-Class:com.headfirstjava.PackageExcise
。在classes目录下执行jar语句打包,这里只要指定com路径就行。
jar -cvmf manifest.txt packEx.jar com
jar -xf packEx.jar
解压后会发现有META-INF
目录,其下有MANIFEST.MF
文件,即为写入的对应文件。制做可执行jar程序;编写jnlp文件;二者均放入Web服务器;Web服务器设定新类型application/x-java-jnlp-file
;设定网页连接到jnlp文件<a href="MyApp.jnlp">Launch My App</a>
rmic MyRemoteImpl
),启动RMI registry(rmiregistry
),启动远程服务(Naming.rebind("Remote Hello", serviceMyRemote)
)。(MyRemote)Naming.lookup("rmi://127.0.0.1/Remote Hello")
),RMIregistry返回stub对象,客户端调用stub上的方法;Jini也使用RMI,但具备自适应探索(接收服务注册和客户端调用查询)和自恢复网络(用心跳检查服务)的功能;
断言能够用来测试,它比println的好处是没有特别设定的话,它会自动被JVM忽略,也可专门打开断言调试程序。
assert (height > 0) : "height = " + height + " weight = " + weight; //冒号后面的语句能够是任何返回非null值得语句,但必定要注意不要在这里改变对象的状态 //断言的编译和普通编译没差异,执行时有差别。 javac TestDriveGame.java java -ea TestDriveGame
new Foo().go()
是一个调用go方法,但又不须要维持对Foo引用的方式;匿名内部类。
//button.addActionListener(quitListener); //一般是传递一个内部类的实例 //虽然ActionListener是个接口,并且咱们不能声明一个接口的实例,但匿名内部类是个例外 button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev){ System.exit(0); } });
new int [4][2]
实际上是建立一个包含四个元素的数组,每一个元素是一个长度为2的数组。public enum Members {JERRY, BOBBY, PHIL};
能够在enum中加入构造函数,方法、变量和特定常量的内容;
暂无