第1章--抽象与接口

1.1 抽象

An abstract class can be created without abstract methods, the purpose of doing this is to prevent instantiating the class.

A class with any abstract method must be abstract.

1.2 数据与表现分离

separation of the logical layer and the graphical interface.

责任驱动:whose responsibility?

1.3 接口

接口所有的方法都是没有方法体的,而且都是public abstract,即使你没有这样声明。

接口中的所有成员变量都是public static final的变量,并且必须有定义初始化,因为所有变量都必须在编译的时候有确定值。

Java不允许多继承(一个类有两个父类),但是允许一个类实现多个接口,也允许一个接口从多个接口得到继承,但是不允许接口从类继承。

接口--任何需要传入传出的一定是接口而不是具体的类

pro: 适合多人同时写一个大程序

con: 代码量膨胀起来很快

第2章--异常

2.1 异常的捕捉

// Question:
// how is the ArrayIndexOutOfBoundsException thrown by f() ? public class ExceptionThrown { public static void f() {
int[] a = new int[10];
a[10] = 10;
System.out.println("hello");
} public static void g() {
f();
} public static void h() {
int i = 10;
if (i < 100) {
g();
}
} public static void k() {
try {
g();
} catch (NullPointerException e) {
System.out.println("k()");
}
} public static void main (String[] args) {
try {
k();
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception Caught");
System.out.println(e);
e.printStackTrace();
}
}
}

捕捉异常后 可以处理异常,也可再次抛出

catch(Exception e) {

...

throw e;

}

finally{} -- execute finally block after try/catch.

2.2 异常的抛出和声明

若函数可能抛出异常,就必须在函数头部声明 throws ...

若调用一个声明了会抛出异常的函数,这需要try/catch来解决异常或重新抛出异常。

所有异常都是Exception类的子类。

捕捉异常时可以catch到异常的子类。

多句catch语句时会按照先后顺序匹配,若匹配到则不会继续匹配。

若同时有两句catch捕捉子类和父类异常,

注意"Unreachable catch block for child Exception" if child exception is put after the catch parent exception.

当覆盖一个函数的时候,子类的函数声明抛出的异常不能比被覆盖的父类函数声明抛出的异常多。

因为有可能拿着子类的对象当成父类的对象来看待: upper cast

public class A {
public void f() throws AException {}
} public class A1 extends A {
public void f() {} // works ok
public void f() throws AException {} // works ok
public void f() throws AException, BException {} // Error: Exception BException is not compatible with throws clause in A.f()
}

在子类的构造函数中,必须声明父类可能抛出的全部异常。

因为子类的构造器会自动调用父类的构造器。

第3章--IO

3.1 流

处理输入输出的方法:stream -- unidirectional; one-dimensional.

java.io: Package

InputStream & OutputStream -- abstract class in java.io

InputStream:

read(); read(byte b[]); read(byte[], int off, int len); --stream of bytes

int available(); mark(); reset(); markSupported(); close();

public class InputStreamTest {

    public static void main(String[] args) {
System.out.println("Ready to read in: ");
byte[] buffer = new byte[1024];
try {
int len = System.in.read(buffer); // how many bytes read in
String s = new String(buffer, 0 ,len); // start at 0, with length len
System.out.println("read in " + len + " bytes.");
System.out.println(s);
System.out.println("length of s: " + s.length());
} catch (IOException e) {
e.printStackTrace();
}
}
}

when the input stream contains Chinese characters, the value of len would be different from the value of s.length()

OutputStream:

write(); write(int b); write(byte b[]); write(byte b[], int off, int len);

flush()--; close();

File stream 文件流:

FileInputStream & FileOutputStream -- 实际工程中较少使用:常用在内存数据或通信数据上建立的流;具体的文件读写有更专业的类如配置文件和日志文件.

public static void main(String[] args) {
System.out.println("prompt");
byte[] buffer = new byte[10];
for(int i = 0; i < buffer.length; i++) {
buffer[i] = (byte) i;
}
try {
FileOutputStream out = new FileOutputStream("a.dat");
out.write(buffer);
// a file called a.dat will be created of size 10 bytes
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

流过滤器:

以一个介质流对象为基础,层层构建过滤器流,最终形成的流对象能在数据的输入输出过程中,逐层使用过滤器流的方法来读写数据。

    public static void main(String[] args) {
System.out.println("prompt"); // data stream: input/output the primitive types value
DataOutputStream out;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("a.dat")));
// nested stream -- bytes from FileOutputStream to BufferedOutputStream, to DataOutputStream
// int i = 0xcafebabe; // hex
int i = 123456; // what is written in the file is binary
out.writeInt(i);
out.close(); DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("a.dat")));
int j = in.readInt();
in.close();
System.out.println(j); } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

3.2 文本流

The class we use previously (Data stream) is only available for dealing with data of primitive types (binary data).

What if we wanna handle text? -- Reader & Writer.

    public static void main(String[] args) {
System.out.println("prompt"); try {
PrintWriter out = new PrintWriter (
new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream("a.txt"))));
// FileOutputStream: bytes
// OutputStreamWriter: the bridge between stream and writer
int i = 123456;
out.println(i);
out.close(); // BufferedReader
BufferedReader in = new BufferedReader(
new InputStreamReader(
new FileInputStream("src/ReaderWriter.java")));
String line;
while ((line = in.readLine()) != null) {
// read in line by line
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Other classes:

LineNumberReader -- is able to get the line number and switch between lines

FileReader -- is the child class of InputStreamReader.

FileReader(File file);/ FileReader(String fileName); -- create a reader on a file directly.

文件编码方式的影响:

国标GB码:2bytes一个汉字

Unicode编码:所有平台上通用。

UTF-8:如果全部是英文字符,一个byte就能表示一个英文字符;如果有汉字(对他们来说不常见),这需要(可能)3个字节表示

若:上述程序读入的是UTF-8编码的文件,则会输出乱码--FileInputStream处理二进制数据后交给InputStreamReader处理文本(二进制转换为文本:default方法:系统默认方式)

程序改进--在InputStreamReader中给定处理方式new InputStreamReader(new FileInputStream("utf8.txt"), "utf8"));

(创建使用给定字符集的InputStreamReader: InputStreamReader(InputStream in, Charset cs);

创建使用给定字符集解码器的InputStreamReader: InputStreamReader(InputStream in, CharsetDecoder dec);

创建使用指定字符集的InputStreamReader: InputStreamReader(InputStream in, String charsetName);)

面对繁多的输入输出类,如何选择呢?

是二进制数据?-- InputStream

否 -- 表达的是文本? -- Reader (readLine...)

表达的是基本数据类型? -- Scanner(nextInt\nextDouble...)

3.3 流的应用 (instances)

network socket

public static void main(String[] args) {

        try {
// construct connection
Socket socket = new Socket(InetAddress.getByName("localhost"), 12345);
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())));
out.println("Hello"); // write Hello
out.flush(); // kinda like refresh // Read in
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String line;
line = in.readLine();
System.out.println(line); out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
} }

在terminal中打开nc -l 12345端口后,运行程序。

read()函数是阻塞的,在读到所需的内容之前会停下来等(基于read()的函数也是如此,如nextInt(), readLine())

常用单独的线程来做socket读入的等待,或使用nio的channel选择机制

对于socket,可以设置SO时间:setSoTimeout(int timeOut);

对象串行化:将类整个写到流里去 (Interface Serialization)

ObjectInputStream & ObjectOutputStream

public static void main(String[] args) {
Student s1 = new Student("John", 18, 5);
System.out.println("s1" + s1); try {
ObjectOutputStream out;
out = new ObjectOutputStream (
new FileOutputStream("obj.dat"));
out.writeObject(s1);
out.close();
} catch (IOException e) {
e.printStackTrace();
} ObjectInputStream in;
try {
in = new ObjectInputStream(
new FileInputStream("obj.dat"));
Student s2 = (Student)in.readObject();
System.out.println("s2" + s2);
in.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} }

第4章--设计原则

4.1 城堡游戏(例子)

package castle;

public class Room {
public String description;
public Room northExit;
public Room southExit;
public Room eastExit;
public Room westExit; public Room(String description)
{
this.description = description;
} 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 = south;
if(west != null)
westExit = west;
} @Override
public String toString()
{
return description;
}
}
package castle;

import java.util.Scanner;

public class Game {
private Room currentRoom; public Game()
{
createRooms();
} private void createRooms()
{
Room outside, lobby, pub, study, bedroom; // 制造房间
outside = new Room("城堡外");
lobby = new Room("大堂");
pub = new Room("小酒吧");
study = new Room("书房");
bedroom = new Room("卧室"); // 初始化房间的出口
outside.setExits(null, lobby, study, pub);
lobby.setExits(null, null, null, outside);
pub.setExits(null, outside, null, null);
study.setExits(outside, bedroom, null, null);
bedroom.setExits(null, null, null, study); currentRoom = outside; // 从城堡门外开始
} private void printWelcome() {
System.out.println();
System.out.println("欢迎来到城堡!");
System.out.println("这是一个超级无聊的游戏。");
System.out.println("如果需要帮助,请输入 'help' 。");
System.out.println();
System.out.println("现在你在" + currentRoom);
System.out.print("出口有:");
if(currentRoom.northExit != null)
System.out.print("north ");
if(currentRoom.eastExit != null)
System.out.print("east ");
if(currentRoom.southExit != null)
System.out.print("south ");
if(currentRoom.westExit != null)
System.out.print("west ");
System.out.println();
} // 以下为用户命令 private void printHelp()
{
System.out.print("迷路了吗?你可以做的命令有:go bye help");
System.out.println("如:\tgo east");
} private void goRoom(String direction)
{
Room nextRoom = null;
if(direction.equals("north")) {
nextRoom = currentRoom.northExit;
}
if(direction.equals("east")) {
nextRoom = currentRoom.eastExit;
}
if(direction.equals("south")) {
nextRoom = currentRoom.southExit;
}
if(direction.equals("west")) {
nextRoom = currentRoom.westExit;
} if (nextRoom == null) {
System.out.println("那里没有门!");
}
else {
currentRoom = nextRoom;
System.out.println("你在" + currentRoom);
System.out.print("出口有: ");
if(currentRoom.northExit != null)
System.out.print("north ");
if(currentRoom.eastExit != null)
System.out.print("east ");
if(currentRoom.southExit != null)
System.out.print("south ");
if(currentRoom.westExit != null)
System.out.print("west ");
System.out.println();
}
} public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Game game = new Game();
game.printWelcome(); while ( true ) {
String line = in.nextLine();
String[] words = line.split(" ");
if ( words[0].equals("help") ) {
game.printHelp();
} else if (words[0].equals("go") ) {
game.goRoom(words[1]);
} else if ( words[0].equals("bye") ) {
break;
}
} System.out.println("感谢您的光临。再见!");
in.close();
} }

4.2 消除代码复制

duplication -- bad for maintenance.

solution--using methods; inheritance.

System.out.println("你在" + currentRoom);
System.out.print("出口有: ");
if(currentRoom.northExit != null)
System.out.print("north ");
if(currentRoom.eastExit != null)
System.out.print("east ");
if(currentRoom.southExit != null)
System.out.print("south ");
if(currentRoom.westExit != null)
System.out.print("west ");
System.out.println();

duplications in printWelcome() and goRoom();

4.3 封装

encapsulation.

good design: low coupling & high cohesion.

for code modification & code reuse.

Lower coupling by using encapsulation

bad design: variables in Room set as public

solution: private visualization should be used

but how to access these variables? add getters? Not an OOP solution.

--  coupling: what does these exits used for?

We can make Room class tell Game about its exits, rather than figure it out in Game class.

getExitDesc() in Room

public String getExitSDesc() {
StringBuffer sb = new StringBuffer(); 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();
}

the reason why not using String s = ""; s+="north ";... -- immutable -> new and replace -> to much cost.

an efficient way to do this: StringBuffer.

-- coupling: same for move operation in Game.goRoom()

public Room moveToNextRoom(String direction) {
Room nextRoom = null;
if(direction.equals("north")) {
nextRoom = northExit;
}
if(direction.equals("east")) {
nextRoom = eastExit;
}
if(direction.equals("south")) {
nextRoom = southExit;
}
if(direction.equals("west")) {
nextRoom = westExit;
}
return nextRoom;
}

4.4 可扩展性

可扩展性的意思就是代码的某些部分不需要经过修改就能适应将来可能的变化。

add functions: go up/down:

用容器来实现灵活性--原本: 用成员变量来表示Room的方向,增减方向需要改变代码。

solution: 用hash table来表示方向,那么方向就不是“硬编码”的了。

four private Room variables should not be created in Room class directly -- changing to use HashMap<String, Room> instead.

adjust the method setExits();

public void setExit(String dir, Room room) {
exits.put(dir, room);
}

change the initialization of the exits to:

outside.setExit("east", lobby);
outside.setExit("south", study);
outside.setExit("west", pub);
lobby.setExit("west", outside);
pub.setExit("east", outside);
study.setExit("north", outside);
study.setExit("east", bedroom);
bedroom.setExit("west", study); // extended exits
lobby.setExit("up", pub);
pub.setExit("down", lobby);

4.5 框架加数据

进一步加强可拓展性:从程序中识别出框架和数据,以代码实现框架,将部分功能以数据的方式加载。

上一小节中的exits改动就是框架的使用。

还有一个地方也可以使用到这个理论来改良代码质量:读取指令的部分

while ( true ) {
String line = in.nextLine();
String[] words = line.split(" ");
if ( words[0].equals("help") ) {
game.printHelp();
} else if (words[0].equals("go") ) {
game.goRoom(words[1]);
} else if (words[0].equals("bye") ) {
break;
}
readInCmd();
}

while loop中的String-method pair可不可以也用HashMap的框架表示呢?

借助子类class中的override method来实现。

    public void play() {
Scanner in = new Scanner(System.in);
while ( true ) {
String line = in.nextLine();
String[] words = line.split(" "); CmdHandler handler = handlers.get(words[0]);
if (handler != null) {
handler.cmdHandling();
if (handler instanceof ByeHandler) {
break;
} else if (handler instanceof GoHandler) {
if (words.length == 2) {
((GoHandler)handler).cmdHandling(words[1]);
} else {
System.out.println("Invalid Command (Usage: go dir)\n");
}
}
} else {
System.out.println("Invalid Command\n");
}
}
in.close();
}
public class CmdHandler {

    public void cmdHandling() {

    }
} public class GoHandler extends CmdHandler{ private Game game; public GoHandler(Game game) {
this.game = game;
} public void cmdHandling(String dir) {
game.goRoom(dir);
}
} public class HelpHandler extends CmdHandler{ public void cmdHandling() {
System.out.println("迷路了吗?你可以做的命令有:go bye help");
System.out.println("如:\tgo east");
}
} public class ByeHandler extends CmdHandler{ public void cmdHandling() {
System.out.println("感谢您的光临。再见!");
}
}

之后,若是想要加入新的cmd,添加Handler的子类即可。

第5章--设计模式

5.1 注入控制反转

GUI(Graphic User Interface):

部件:创建GUI的独立部分,比如按钮、菜单、菜单项、选择条等

布局:如何在屏幕上放置组件 -- 通过layout manager布局管理器实现

容器:可以在容器frame中放置部件(需要指定位置BorderLayout)(容器本身也是部件)

事件处理:用来响应用户的输入。用户激活一个部件,系统就会产生一个事件,应用程序就可以收到关于这个时间的通知(调用一个方法)。

BorderLayout:NORTH/ SOUTH/ EAST/ WEST/ CENTER. (default-CENTER) (overwrite if the position is the same)

Swing:event handling处理用户输入。

动作事件:点击按钮或选中菜单项

鼠标事件:点击或移动鼠标

窗口事件:框架被关闭或最小化

等等。

Q: How does a JButton object invoke the methods in my class?

A: One way can be done on our own: have a class MyButton extends JButton and override the doPressed() method to invoke myMethod.

A: What Swing does: 注入反转(反转控制)

JButton class; ActionListener interface;

JButton.addActionListener()/JButton.removeActionListener().

ActionListener.actionPerformed();

implement actionPerformed()

when click the JButton, check any actionListener related

JButton knows its registered ActionListener

invoke ActionListener.actionPerformed();

// add button
JButton btnStep = new JButton("下一步");
frame.add(btnStep, BorderLayout.NORTH); // which component, and where
btnStep.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent e) {
step();
frame.repaint();
}
});

上例中:ActionListener作为一个内部类(一个类定义在另一个类的内部,从而成为外部类的一个成员,具有和成员变量成员方法相同的性质)

内部类的最重要的特点就是能够访问外部类的所有成员(包括私有成员);当外部是函数时,只能访问那个函数里的final变量(?)。

此外:ActionListener也是一个匿名类(在new对象的时候给出的类的定义),匿名类可以继承某类,也可以实现某接口

5.2 MVC设计模式

JTable: separating the data and representation.

    public static void main(String[] args) {
JFrame frame = new JFrame();
JTable table = new JTable(new CurriculumData());
// JTable cannot display all of its content
JScrollPane panel = new JScrollPane(table);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setSize(400, 400);
frame.setVisible(true);
}

CurriculumData is a class that stores the data

import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel; public class CurriculumData implements TableModel { private String[] title = {
"周一","周二","周三","周四","周五","周六","周日"
}; private String[][] curriculum = new String[8][7]; @Override
public int getRowCount() {
return 8;
} @Override
public int getColumnCount() {
return 7;
} @Override
public String getColumnName(int columnIndex) {
// the name of each column
return title[columnIndex];
} @Override
public Class<?> getColumnClass(int columnIndex) {
// the data type of each column
return String.class;
} @Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return true;
} @Override
public Object getValueAt(int rowIndex, int columnIndex) {
// get the data value at a particular cell
return curriculum[rowIndex][columnIndex];
} @Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
// set the data value at a particular cell
curriculum[rowIndex][columnIndex] = (String) aValue;
} @Override
public void addTableModelListener(TableModelListener l) {
// TODO Auto-generated method stub
} @Override
public void removeTableModelListener(TableModelListener l) {
// TODO Auto-generated method stub
}
}

what happens inside is: There is a Table Model object between JTable and JTableData as the interface.

|

\|/

MVC (Model, View, Control)

模型:保存和维护数据,提供接口让外部(Control)修改数据,notify表现(View)刷新呈现的数据

表现:从模型获得数据,根据数据画出表现

控制:从用户得到输入,根据输入调用Model的接口来调整数据

NB: Control和View没有直接的联系

好处:每一个部分的实现都很单纯,比如View只需知道每次全部重画一遍,无需在意修改的细节

上例中:Model (TableModel); View&Control (JTable) -- 常见MVC实现方式,将View&Control合并(都是显示部分)

Java应用基础微专业-设计篇的更多相关文章

  1. Java应用基础微专业-工程篇

    第1章-命令行 1.1 命令行基础 ls -a: list all files (including hidden files) .DS_Store: files detailed informati ...

  2. Java应用基础微专业-进阶篇

    第1章--使用对象 1.1 字符类型 char c = 65; // char --> int char c = '\u0041'; // \u: unicode + (Hex 41--> ...

  3. Java应用基础微专业-入门篇

    第1章--用程序来做计算 1.1 第一个Java程序 Mac version: Preference -> General -> Keys -> Search "Conte ...

  4. 《手把手教你》系列基础篇(九十六)-java+ selenium自动化测试-框架之设计篇-跨浏览器(详解教程)

    1.简介 从这一篇开始介绍和分享Java+Selenium+POM的简单自动化测试框架设计.第一个设计点,就是支持跨浏览器测试. 宏哥自己认为的支持跨浏览器测试就是:同一个测试用例,支持用不同浏览器去 ...

  5. 总结删除文件或文件夹的7种方法-JAVA IO基础总结第4篇

    本文是Java IO总结系列篇的第4篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  6. 总结java中文件拷贝剪切的5种方式-JAVA IO基础总结第五篇

    本文是Java IO总结系列篇的第5篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  7. 归纳从文件中读取数据的六种方法-JAVA IO基础总结第2篇

    在上一篇文章中,我为大家介绍了<5种创建文件并写入文件数据的方法>,本节我们为大家来介绍6种从文件中读取数据的方法. 另外为了方便大家理解,我为这一篇文章录制了对应的视频:总结java从文 ...

  8. 总结java创建文件夹的4种方法及其优缺点-JAVA IO基础总结第三篇

    本文是Java IO总结系列篇的第3篇,前篇的访问地址如下: 总结java中创建并写文件的5种方式-JAVA IO基础总结第一篇 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇 ...

  9. Java Web基础 --- Servlet 综述(理论篇)

    摘要: Web 技术成为当今主流的互联网 Web 应用技术之一,而 Servlet 是 Java Web 技术的核心基础.本文首先从请求/响应架构应用的大背景谈起 Servlet 的由来,明确 Ser ...

随机推荐

  1. JAVA Collections常用方法

    /* 集合框架的工具类 Collections: */ import java.util.*; class Test { public static void main(String [] args) ...

  2. 转:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 解决方案

    转:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure 解决方案javax.net.ssl.SSL ...

  3. Kettle api 二次开发之 日志的保存

    使用kettle做数据抽取的时候可以使用图形化的工具配置日志保存参数,选择数据库连接,输入日志表名称, 点击sql 执行对应的sql创建日志表即可. 点击保存之后,日志配置会保存在trans或者job ...

  4. Faster Alternatives to glReadPixels and glTexImage2D in OpenGL ES

    In the development of Shou, I’ve been using GLSL with NEON to manipulate image rotation, scaling and ...

  5. Sharepoint COMException 0x81020037

    研究了很久,ListItem在保存的时候一直在出Sharepoint COMException 0x81020037 根据错误提示,是保存的时候发生冲突导致,苦思冥想,终于解决了,原因如下: List ...

  6. 设计一个方法injectBeforeAsyncSend,能够实现如下功能:在发起异步请求之前打印出请求的类型、URL、method、body、timestamp 等信息。

    异步请求逻辑注入 工作中我们需要对异步请求的请求信息打印日志,但是又不能耦合在业务代码中打印.请设计一个方法injectBeforeAsyncSend,能够实现如下功能:在发起异步请求之前打印出请求的 ...

  7. 阿里前端测试题--关于ES6中Promise函数的理解与应用

    今天做了阿里前端的笔试题目,原题目是这样的 //实现mergePromise函数,把传进去的数组顺序先后执行,//并且把返回的数据先后放到数组data中 const timeout = ms => ...

  8. Adnroid studio 无法 Build APK(s)

    报错 Error:java.nio.file.AccessDeniedException: C:\Program Files\Android\android-sdk-windows\.android\ ...

  9. windows安装多个版本的jdk,解决java-version和javac-version版本不一致的问题

    系统先装了jdk1.8 ,环境变量里配置的是jdk1.8,java -version 与javac -version 版本一致. 然后安装了jdk1.6 ,环境变量java_home 改成了1.6,但 ...

  10. String.Format() 方法

    一 定义 String.Format() 是将指定的 String类型的数据中的每个格式项替换为相应对象的值的文本等效项. string p1 = "Jackie"; string ...