标签:方式 sock 另一个 抽象方法 端口 protect edit lower 水平
Java 编程基础............................................................................................................ - 3 -
一、 前言....................................................................................................... - 3 -
1. JAVA 软件工程师的岗位要求................................................................. - 3 -
二、 Java概述:............................................................................................ - 4 -
1. Java的三种技术架构.............................................................................. - 4 -
2. JDK、JRE、JVM三者间的关系............................................................. - 4 -
3. Java运行环境配置................................................................................. - 5 -
4. Java与Javac命令................................................................................. - 6 -
5. Java编译过程........................................................................................ - 7 -
6. Java内存处理机制................................................................................. - 7 -
7. 常用DOS命令....................................................................................... - 7 -
三、 Java编程风格与命名规范....................................................................... - 8 -
1. 格式规范................................................................................................ - 8 -
2. 命名规范................................................................................................ - 8 -
四、 语法基本元素......................................................................................... - 9 -
1. 关键字................................................................................................... - 9 -
2. 标识符................................................................................................... - 9 -
3. 数据类型、常量和变量......................................................................... - 10 -
4. 运算符和表达式.................................................................................... - 11 -
五、 流程控制.............................................................................................. - 14 -
1. 循环语句.............................................................................................. - 14 -
2. 判断语句.............................................................................................. - 14 -
3. 跳转语句.............................................................................................. - 14 -
4. flag 或index标记的用法..................................................................... - 15 -
六、 数组..................................................................................................... - 16 -
1. 数组的常用操作................................................................................... - 16 -
2. 二维数组.............................................................................................. - 17 -
Java 面向对象.......................................................................................................... - 19 -
一、 前言..................................................................................................... - 19 -
二、 类和对象.............................................................................................. - 19 -
1. 类和对象的定义................................................................................... - 19 -
2. 类的创建和使用................................................................................... - 19 -
3. 对象的创建和使用................................................................................ - 20 -
4. 成员变量VS局部变量.......................................................................... - 20 -
5. 成员方法VS方法................................................................................. - 21 -
6. 构造方法.............................................................................................. - 22 -
7. 补充几点.............................................................................................. - 22 -
三、 封装、继承和多态................................................................................ - 25 -
1. 封装..................................................................................................... - 25 -
2. 继承..................................................................................................... - 26 -
3. 多态..................................................................................................... - 27 -
四、 抽象类和接口....................................................................................... - 30 -
1. 抽象类(abstract).............................................................................. - 30 -
2. 接口(interface)................................................................................ - 31 -
3. 抽象类和接口的对比............................................................................ - 32 -
五、 异常..................................................................................................... - 33 -
1. JAVA异常............................................................................................ - 33 -
2. 处理异常机制....................................................................................... - 34 -
3. 捕获异常try / catch 和 finally.............................................................. - 34 -
4. 抛出异常 throws和throw.................................................................... - 35 -
5. Java常见异常...................................................................................... - 35 -
6. 自定义异常.......................................................................................... - 36 -
7. Java异常处理的原则和技巧................................................................. - 36 -
8. 补充几点.............................................................................................. - 36 -
六、 面向对象的几点猜想............................................................................ - 36 -
Java 高级特性.......................................................................................................... - 37 -
一、 集合框架和泛型................................................................................... - 37 -
1. 集合 框架 API..................................................................................... - 37 -
2. Iterator 迭代器.................................................................................... - 40 -
3. Collections包装类............................................................................... - 41 -
4. 补充几点.............................................................................................. - 42 -
5. 泛型..................................................................................................... - 42 -
二、 实用类................................................................................................. - 42 -
1. 枚举..................................................................................................... - 43 -
2. 包装类................................................................................................. - 43 -
3. Math类................................................................................................ - 44 -
4. String类.............................................................................................. - 44 -
5. StringBufffer类和StringBulider类...................................................... - 45 -
6. 日期时间类.......................................................................................... - 45 -
7. Random类........................................................................................... - 46 -
三、 输入/输出、序列化和反射.................................................................... - 46 -
1. File类的操作....................................................................................... - 46 -
2. Java的流............................................................................................. - 47 -
3. 读写文本文档....................................................................................... - 47 -
4. 读写二进制文档................................................................................... - 50 -
5. 重定向标准 I/O.................................................................................... - 51 -
6. 序列化与反序列化................................................................................ - 51 -
7. 反射机制.............................................................................................. - 52 -
8. 补充几点.............................................................................................. - 52 -
四、 注解和多线程....................................................................................... - 53 -
1. 注解..................................................................................................... - 53 -
2. 多线程................................................................................................. - 54 -
五、 网络编程.............................................................................................. - 57 -
1. 网络基础知识....................................................................................... - 57 -
2. InetAddress......................................................................................... - 58 -
3. URL类................................................................................................. - 58 -
4. TCP编程............................................................................................. - 59 -
5. UDP编程............................................................................................. - 63 -
6. 注意问题.............................................................................................. - 65 -
六、 XML..................................................................................................... - 65 -
1. XML 基础............................................................................................ - 65 -
2. XML 注释............................................................................................ - 65 -
3. XML 解析............................................................................................ - 65 -
七、 GUI...................................................................................................... - 68 -
八、 正则表达式.......................................................................................... - 73 -
1991 年Sun公司的James Gosling等人开始开发名称为 Oak 的语言,希望用于控制嵌入在有线电视交换盒、PDA等的微处理器;1994年将Oak语言更名为Java;
Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对web开发。
Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础。
Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序。
JDK是整个JAVA的核心,包括了Java运行环境JRE(Java Runtime Envirnment)、一堆Java工具(Javac/Java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。
在JDK的安装目录下有一个名为jre的目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。
Java程序的运行环境,Java运行的所需的类库+JVM(Java虚拟机)。与JDK不同,JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器),只是针对于使用Java程序的用户。
Java虚拟机的缩写,是整个Java实现跨平台的最核心的部分,所有的Java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。
也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。
只有JVM还不能成class的执行,因为在解释class的时候JVM需要调用解释所需要的类库lib,而jre包含lib类库。
作用是指定命令搜索路径,在shell下面执行命令时,它会到PATH变量所指定的路径中查找看是否能找到相应的命令程序。我们需要把 jdk安装目录下的bin目录增加到现有的PATH变量中,bin目录中包含经常要用到的可执行文件如Javac/Java/Javadoc等,设置好 PATH变量后,就可以在任何目录下执行Javac/Java等工具了。
作用是指定类搜索路径,要使用已经编写好的类,前提当然是能够找到它们了,JVM就是通过CLASSPTH来寻找类的。我们 需要把jdk安装目录下的lib子目录中的dt.jar和tools.jar设置到CLASSPATH中,当然,当前目录“.”也必须加入到该变量中。
它指向jdk的安装目录,Eclipse/NetBeans/Tomcat等软件就是通过搜索JAVA_HOME变量来找到并使用安装好的jdk。
Java_Home:C:\Program Files\Java\jdk1.7.0_07
Path: %Java_Home%\bin;%Java_Home%\jre\bin;
ClassPath:. ; %Java_Home%\bin;%Java_Home%\lib\dt.jar;%Java_Home%\lib\tools.jar
特点:系统默认先去当前路径下找要执行的程序,如果没有,再去path中设置的路径下找
set path=%path%;C:\Program Files\Java\jdk\bin set classpath=XXX
注释:环境变量的配置已经完成,DOS命令下输入Java/Javac/Java –version检测。
如果没有定义环境变量classpath,Java启动JVM后,会在当前目录下查找要运行的类文件;如果指定了classpath,那么会在指定的目录下查找要运行的类文件。
还会在当前目录找吗?两种情况:
Java是分两部分的:一个是编译,一个是运行。
待补充~
md |
创建文件夹 |
cd |
进入文件夹 |
del |
删除文件夹 |
copy |
复制文件 |
rd |
删除文件夹 |
cd.. |
后退一级 |
cls |
清屏 |
help |
帮助 |
dir |
列出目录 |
cd\ |
进入根目录 |
ren |
重命名 |
|
|
详见常用DOS命令大全及其用法
a) 缩进嵌套的代码
b) 断开很长的句子
c) 使用空白
d) 不要直接使用Tab控制符
JAVA源文件名必须和源文件中所定义的类的类名相同。且不能为关键字
Package名的第一部分应是小写ASCII字符,并且是顶级域名之一,通常是com、edu、gov、mil、net、org或由ISO标准3166、1981定义的国家唯一标志码。Package名的后续部分由各组织内部命名规则决定,内部命名规则指定了各组件的目录名,所属部门名、项目名等。
Class名应是首字母大写的名词, 而且大写中间单词的首字母。命名时应该使其简洁而又具有描述性。异常类的命名,应以Exception结尾。Interface的命名规则与Class相同。
常量名的字母应全部大写,不同单词之间通过下划线连接,并且名字组合应该赋予含义。
普通变量名的首字母小写,其它每个单词的首字母大写。命名时应该使其简短而又有特定含义,简洁明了的向使用者展示其使用意图。
所谓约定变量,是指那些使用后即可抛弃(throwaway)的临时变量。通常i、j、k、m和n代表整型变量;c、d和e代表字符型变量。
方法名的第一个单词应是动词,并且首字母小写,其它每个单词首字母大写。
选择有意义的名称作为方法的参数名。可能的话,选择和需要赋值的字段一样的名字。
详见Java编程风格与命名规范-ZZ
a) 定义:被JAVA语言赋予了特殊含义的单词。
b) 特点:关键字中所有字母都为小写。
c) 注意:goto和const作为保留字存在,目前并不使用。
a) 含义:标识符就是给类,接口,方法,变量等起名字时使用的连续字符序列。
b) 组成规则:① 英文大小写字母A~Z和a~z ② 数字字符0~9 ③ $ 和 _
c) 注意事项:① 不能以数字开头 ② 不能是Java中的关键字 ③ 区分大小写
④ 不能有空格
byte、short、int、long、float、double、char、boolean
数组、类、接口。
分类 |
不同类型 |
关键字 |
字节数 |
取值范围 |
默认值 |
整数型 |
字节型 |
byte |
1个字节 |
-27~27-1(-128~127) |
0 |
短整型 |
short |
2个字节 |
-215~215-1(-32768~32767) |
0 |
|
整型 |
Int (默认) |
4个字节 |
-231~231-1 |
0 |
|
长整型 |
long |
8个字节 |
-263~263-1 |
0 |
|
文本型 |
字符型 |
char |
2个字节 |
0~216-1(从0~65536) |
‘\u0000’ |
浮点型 |
单精度浮点型 |
float |
4个字节 |
大约±3.40282347E+38F (有效位数为6~7位) |
0.0f |
双精度浮点型 |
Double (默认) |
8个字节 |
大约±1.79769313486231570E+308 (有效位数为15位) |
0.0d |
|
逻辑型 |
布尔型 |
boolean |
1个字节 |
True/false |
false |
级别从低到高为:(byte--> short),char (这两个平级)--> int--> float--> long--> double
补充: 不同的字符所占的字节是不同的。详见输入输出章节之字符编码。
0x 0
不同的基本数据类型之间进行运算时需要进行类型转换,除boolean类型外所有的基本数据类型都需要考虑类型转换,其主要应用在算术运算和赋值运算时。
正确举例:String a = integer.toString(2)或int i = integer.parseInt(s);
所有局部变量在使用前都得初始化。详见类与对象部分。
在程序执行的过程中其值不可以发生改变的量,Java中常量可分为字面值常量和自定义常量。 eg. final double PI = 3.14;
|
3.14 314.0 时 .314
3.14e2 3.14E2 314E2
在计算机内,有符号数有3种表示法:原码、反码和补码。所有数据的运算都是采用补码进行的。
u [+1] = [00000001]原 = [00000001]反 = [00000001]补
u [-1] = [10000001]原 = [11111110]反 = [11111111]补
参考:
表达式是由运算符与操作数组合而成的,运算符指明对操作数的运算方式。组成表达式的Java操作符有很多种。运算符按照其要求的操作数数目来分,可以有单目运算符、双目运算符和三目运算符,它们分别对应于1个、2个、3个操作数。运算符按其功能来分,有算术运算符、赋值运算符、关系运算符、逻辑运算符、位运算符和其他运算符。
优先级 |
运 算 符 |
含义描述 |
1 |
( ) ,. , [ ] |
强制运算、方法调用 |
2 |
++ , -- , + , ~(位取反) , !(逻辑取反) |
一元运算、字符串相加 |
3 |
New eg.Type a=new Type() |
创建运算符 |
4 |
* , / , % |
算术运算 乘除、取余 |
5 |
+ , - |
算术运算 加减(正负) |
6 |
<< , >> , >>>(无符号) |
位运算 |
7 |
< , > , <= , >= , instanceof |
比较运算、类运算 |
8 |
= = , ! = , .equals() |
比较运算 |
9 |
& |
逻辑(位)运算 与 |
10 |
^ |
位运算 异或 |
11 |
| |
逻辑(位)运算 或 |
12 |
&& |
逻辑 与(短路) |
13 |
|| |
逻辑 或(短路) |
14 |
?: eg. (关系表达式)?表达式1:表达式2; |
三元 条件运算 |
15 |
= , *= , /= , %= , += , -= |
简单赋值运算 |
16 |
<<= , >>= , >>>= , &= , ^= , |= |
复杂赋值运算 |
(* , / , % , + , - )
(= , *= , /= , %= , += , -=)
(< , > , <= , >= ,= = , ! =) boolean bo=(i==j);
特点:该运算符的特点是:运算完的结果,要么是true,要么是false。
待补充:==与.equals()区别:
(& , | , ^ , ! , && , ||)
逻辑运算符除了 ! 外都是用于连接两个boolean类型表达式。
u 两边结果一样,就为false;
u 两边结果不一样,就为true。
u &:无论左边结果是什么,右边都参与运算(建议短路与);
u &&: 短路与,如果左边为false,那么右边不参数与运算。
u |:两边都运算(建议短路或);
u ||:短路或,如果左边为true,那么右边不参与运算。
用于操作二进制位的运算符;& , | , ^ ,<< , >> , >>>(无符号)
待补充~
在Java中,流程控制分为三种基本结构:顺序结构、分支结构和循环结构。
If 判断: |
else If 判断: |
If 判断(嵌套): |
switch 判断: |
||
if (表达式) { //语句1; } else { //语句2; } 类比: (关系表达式)? 表达式1:表达式2; 注:else语句可用 Continue代替; |
if (表达式1) { //语句1; } else if (表达式2) { //语句2; … } else { //语句3; } |
If (表达式1) { if(表达式2) { //语句1; } else { //语句2; } } else { //语句3; } |
switch (表达式) { case 常量1: 语句1; break; case 常量2: 语句2; break; … default: 语句3; } |
||
while循环: |
do-while循环: |
for循环: |
|||
while(表达式) { //循环体; } |
do{ //循环体; } while(表达式); |
for(初始化;条件;迭代) { //循环体; } |
|||
a) 循环是相同动作的集合.
b) 循环次数确定的情况,通常选用for循环;
循环次数不确定的情况,通常选用while或do-while循环。
c) 初始情况不满足循环条件时,while循环一次都不会执行;
do-while循环不管任何情况都至少执行一次。
d) for 循环,若变量在判断条件内初始化,则作用域为循环体(大括号)内。
e) 嵌套循环判断条件:内层循环一圈,外层循环一次。
a) 多重if与switch选择结构比较
b) else If 顺序进行判断,当前面条件不满足时才进行下一步,条件满足,跳过剩余结构,结束判断语句。
c) switch 后面的小括号中的变量应该是int、short、byte、char、枚举类型、String。
d) switch 可进行语句合并,以进行连续区间判断。(省去语句和break)
a) break:结束判断语句,执行完判断体后的语句后,终止离自己最近的外层循环。
do { String title = input.next(); if (title.equals("exit")) { break; } } while (true); // 跳出死循环 |
b) continue:结束判断语句,终止本次循环,不执行判断体后面语句,进入下一次循环。
public static void main(String[] args) { int i = 0; do { i++; if (i == 3) { // break; // 输出12 continue; // 输出1245 } System.out.println(i); } while (i < 5); } |
c) return:结束当前方法的执行并退出,并返回值到调用该方法的语句处。
for (int i = 0; i < 10; i++) { if (i % 2 != 0) return; System.out.print(i); } // 运行结果:0 |
数组是一个变量,存储相同数据类型的一组数据
步骤 |
举例 |
解释 |
声明 |
int[ ] a; |
告诉计算机数据类型是什么 |
分配空间 |
a = new int[5]; |
告诉计算机分配几个连续的空间 |
赋值 |
a[0] = 8; |
向分配的格子里放数据 |
引用 |
a[0] = a[0] * 10; |
引用数据进行计算 |
数据类型[ ] 数组名 = new 数据类型[大小];
int[ ] scores = {89, 79, 76};
int[ ] scores = new int[ ]{89, 79, 76};
Scanner input = new Scanner (System.in);
for (int i = 0; i < 30; i ++) {
scores[i] = input.nextInt ();}
for (int k = array.length - 1; k >= 0; k--) {// 逆序输出 System.out.print(array[k] + "\t"); } |
for (int temp : array) {// 用for增强型函数对数组进行顺序输出 System.out.println(temp); } |
数组的增添举例: String[] phones = new String[] {"iPones4S", "iPones5", null}; // null 不用加双引号 int index = -1;// 增加监视器 for (int i = 0; i < phones.length; i++) {// 1.增加iPones6 if (phones[i] == null) { index = i; break; } } if (index != -1) { phones[index] = "iPones6"; } else { System.out.println("数组已满"); } System.out.println(Arrays.toString(phones)); |
注释:数组的修改与删除类似
for (int m = 0; m < array.length - 1; m++) { // 冒泡排序 for (int n = 0; n < array.length - 1 - m; n++) { if (array[n] > array[n + 1]) { int temp = array[n]; array[n] = array[n + 1]; array[n + 1] = temp; } } } |
方法名称 |
说明 |
|
Arrays. |
boolean equals(array1,array2) |
比较array1和array2两个数组是否相等 |
sort(array) |
对数组array的元素进行升序排列 |
|
String toString(array) |
将一个数组array转换成一个字符串 |
|
void fill(array,val) |
把数组array所有元素都赋值为val |
|
copyOf(array,length) |
把数组array复制成一个长度为length 的新数组,返回类型与复制的数组一致 |
|
int binarySearch(array, val) |
查询元素值val在数组array中的下标 (要求数组中元素已经按升序排列 |
注释:import java.util.*;
String[][] str = new String[5][]; int[][] scores = new int[][] { { 90, 85, 54 }, { 76, 80 },{ 87 } }; int[][] scores = { { 90, 85, 54 }, { 76, 80 }, { 87 } }; |
public class Case5 { // 二维数组的遍历 public static void main(String[] args) { int[][] scores = new int[][] { { 90, 78, 54 }, { 76 , 80 }, { 87 } }; for (int i = 0; i < scores.length; i++) { //外层数组长度 for (int j = 0; j < scores[i].length; j++) {//内层数组长度 System.out.println(scores[i][j]); } } } } |
public class ConstructorMethod { String name; int age; // 成员变量 public ConstructorMethod(String name, int age) { //有参构造方法,构造方法无返回类型 this.name = name; this.age = age; //实例的属性 = 实参; } public static int Case1() { //成员方法 System.out.println("我是Case1调用"); return 0; } } |
举例:center.name = "北京中心"; //给name属性赋值
举例:center.showCenter(); //调用showCenter()方法
举例:School center = new School();
基本数据类型为初始化为0,布尔类型为false,引用类型为null。
public class Test { public static void main(String[] args) { Cat cat = null; //局部变量需要初始化或传实参 Pet pet = new Cat(); cat = (Cat)cat; } }
class Pet { }
class Cat extends Pet { } |
一般格式:访问修复符 返回值类型 方法名(参数列表){方法体};
类的访问权限有Public和Default两种,类中成员的访问权限有下列四种:
补充:继承权限测试. Package 。
继承权限测试(类之间) & 访问权限测试(属性和方法)测试结果:
u 类的访问修饰符只有public和默认两种。
u 类中成员 public(公共修饰符) --> protected(子类) --> default(包)--> private(私有)
u 局部变量作用域确定,故没有访问修饰符,访问修饰符仅针对成员变量和方法。
u 子类对父类的访问,直接调用属性或方法(其实隐含this.调用)。
u 非继承关系或父类对子类的访问的访问方式,需用对象或类名访问。
u 访问权限是基于继承决定的,继承权限也是一种访问权限。
u 继承则属性和方法归父类和子类共有,但除私有成员不可以访问。
u 子类可以选择重写父类的属性和方法的访问修饰符,权限不能小于父类
方法重载,就是在同一个类里中可以创建多个方法,方法名要一样,参数列表不同,和访问修饰符 、返回值无关。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法,是一个类中多态性的一种表现。
方法重写,在子类和父类之间对,父类的函数进行重新定义。子类名称和参数别表与父类相同,方法体重写。
所谓构造方法,就是构造对象的方法,通过new + 构造方法, 这样就创建了一个新的对象。
public class Test { private String name; public Test(){ this.name = "小新"; } public Test(String name) { System.out.println("我是" +this.name); } public static void main(String[] args) { Test test = new Test("小强"); } } //运行结果:我是null(实参没有该成员变量赋值) |
public class Test { public static void main(String[] args) { for (int i = 0; i < args.length; i++) { System.out.println("args" + i + "=" + args[i]); } } } 输出结果: args0=args1 args1=args2 |
u int month = 4; u int day = input.nextInt(); 注:作为形参的变量的初始化便是传入实参。 |
待补充~
内部类将相关的类组织在一起,从而降低了命名空间的混乱。一个内部类可以定义在另一个类里,可以定义在函数里,甚至可以作为一个表达式的一部分。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象。
http://blog.sina.com.cn/s/blog_accab4a90101gzh2.html
匿名内部类也就是没有名字的内部类,正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写。但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
abstract class Person { public abstract void eat(); }
public class Demo { public static void main(String[] args) { Person p = new Person() { public void eat() { System.out.println("eat something"); } }; p.eat(); } } |
一个类可以使用不包含在任何方法体中的静态代码块,当类被载入时,静态代码块被执行,且只被执行一次,静态块常用来执行类属性的初始化。
static { System.out.println ("Hello Everyone"); } |
方法里不可以定义static
待补充~
这个关键字是一个修饰符,可以修饰类,方法,变量。
public class Test { private String name; //将类的属性进行封装 public String getName() { //并提供可带判断条件的访问方法 return name; }
public void setName(String name) { this.name = name; } } |
将类的属性隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
修改属性的可见性(设为private,防止错误的修改)à创建公有的getter/setter方法(用于属性的读写)à在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)。
class Person { // 父类 private String name; public static int age; public static String sex;
public Person() { // 会自动生成无参构造器 System.out.println("父类构造器"); }; // 但是考虑继承的可靠性,建议写上。
public void setName(String name) { this.name = name; }
public String getName() { return this.name; } }
class Student extends Person { // 子类 private String school;
public Student() { // 子类student中构造 super(); //super只可在子类中使用 System.out.println("子类构造器"); } } public class TestExtendDemo { // 测试类 public static void main(String[] args) { Person.age = 18; Student.age = 19; // 继承父类的成员属性和方法可直接调用 Person.sex = "男"; // 静态变量或方法用类调用 System.out.println(Student.age+Person.sex); Scanner input = new Scanner(System.in); Student someone = new Student(); //创建子类对象的过程 someone.setName(input.next()); // 实例变量和方法用实例调用 System.out.println(someone.getName()); } } |
继承是面向对象最显著的一个特性。多个类中存在相同属性和方法时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和方法,只要继承那个类即可。继承是代码重用的一种方式。Java通过extends关键字来实现单继承。(Is a)
访问父类属性:super.name;
调用父类方法:super.print();
原因:子类的所有构造器中的第一行,其实都有一条隐身的语句super(), super()表示调用父类的无参构造器。子类继承父类中的属性,在new 子类的时候,相应的父类的属性也就拿到了,这就是子类的实例化过程。
然而父类有有参构造器,则无参构造器就不存在了,所以在子类中须在第一行显式调用super(参数),或者在父类中添加一个无参构造器。之所以须在第一行调用,是因为父类的构造器调用以及初始化过程一定在子类的前面。
并且,父类也被new一个对象出来的说法是错误的,举例抽象类可以被继承的,但抽象类不能被实例化。
参考:Java中属性的隐藏与方法的覆盖的区别
参考:静态绑定与动态绑定
u 子类方法重写时方法名、参数、返回值、返回类型均须相同。访问权限不小于父类。
解析:确保子类可以重写父类。父类不能覆盖子类。
u 重写是父子类要么都静态,要么都不静态。
u 子类可以定义与父类同名的静态方法,以便在子类中隐藏父类的静态方法。
u 父类的私有方法不可访问,不能被子类重写。
abstract class Animal { // 因为本身实例化没有意义,所以一般申明为抽象类 Animal() { // 会自动生成无参构造器 }; // 但是考虑继承的可靠性,建议写上。
abstract void eat();// 抽象方法 } class Cat extends Animal { // 1、继承父类 public void eat() { // 2、子类方法的重写 System.out.println("吃鱼"); }
public void catchMouse() { //子类私有方法,只能用子类对象调用 System.out.println("抓老鼠"); } }
class Dog extends Animal { // 1、继承父类 public void eat() { // 2、子类方法的重写 System.out.println("吃骨头"); }
public void kanJia() { System.out.println("看家"); } }
class DuoTaiDemo { // 类名与源文件相同,否则无法运行 public static void main(String[] args) { function(new Cat()); // new Cat() 表示构造一个猫的对象 function(new Dog());
//Animal a; //对象可像变量一样声明和传递参数 //a= new Cat(); //父类为抽象类,不能实例化,但能创建引用 Animal a=new Cat(); // 向上转型 // 类似变量传参,new Cat()是参数 a.eat(); //3.父类对象引用指向子类对象 PS:须先满足前两个条件 }
public static void function(Animal a) { //对象可作变量传递参数 a.eat(); //3.父类对象引用指向子类对象 PS:须先满足前两个条件
if (a instanceof Cat) {// 用于判断对象是否为指定类的实例 Cat c = (Cat) a; // 向下转型,由Animal(父)类转为Cat(子)类 c.catchMouse(); // 向下转型,调用子类特有属性 } else if (a instanceof Dog) { Dog c = (Dog) a; c.kanJia(); } } |
public class Polymorphism { // 多态传参 ,取例 Think in Java void doStuff(Shape s) { // 形参 s.erase(); // ... s.draw(); }
public static void main(String[] args) {
Circle c = new Circle(); // Circle/Triangle/Line是Shape的子类 Triangle t = new Triangle(); Line l = new Line(); doStuff(c); // 实参 doStuff(t); doStuff(l); } } |
指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是方法调用),与方法不同的是对象的属性则不具有多态性。
动态绑定:是指在程序运行时判断所引用对象的实际类型,根据其实际的类型调用其相应的方法,是多态实现的具体形式。执行动态绑定的非静态方法
补充知识:静态绑定:又称为前期绑定在程序编译时进行了绑定,即在还没运行时,就已经加载到内存。执行静态绑定的有变量和静态方法
接口实现,继承父类进行方法重写,同一个类中进行方法重载。当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的该同名方法。
消除类型之间的耦合关系
u 成员变量:在多态中,子父类成员变量同名。
在编译时期:参考的是引用型变量所属的类中是否有调用的成员。(编译时不产生对象,只检查语法错误)
运行时期:也是参考引用型变量所属的类中是否有调用的成员。
简单一句话:无论编译和运行,成员变量参考的都是引用变量所属的类中的成员变量。再说的更容易记忆一些:成员变量à编译运行都看 = 左边。
u 静态函数
编译时期:参考的是引用型变量所属的类中是否有调用的成员。
运行时期:也是参考引用型变量所属的类中是否有调用的成员。
为什么是这样的呢?因为静态方法,其实不属于对象,而是所属于该方法所在的类。
调用静态的方法引用是哪个类的引用调用的就是哪个类中的静态方法。
简单说:静态函数à编译运行都看 = 左边。
u 成员函数
编译时期:参考引用型变量所属的类中是否有调用的方法。
运行事情:参考的是对象所属的类中是否有调用的方法。
为什么是这样的呢?因为在子父类中,对于一模一样的成员函数,有一个特性:覆盖。
简单一句:成员函数,编译看引用型变量所属的类,运行看对象所属的类。
更简单:成员函数à编译看 = 左边,运行看 = 右边。
public abstract class ClassName { int name; abstract void fun(); } |
public interface InterfaceName { public abstract void cry(); } class ClassName implements Interface1,Interface2....{ } |
在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。
接口是抽象方法的集合。如果一个类实现了某个接口,那么它就继承了这个接口的抽象方法。这就像契约模式,如果实现了这个接口,那么就必须确保使用这些方法。
接口主要用来描述类具有什么功能,自身不能做任何事情。具体实现交由实现接口的那个类来完成。
参数 |
抽象类 |
接口 |
默认的方法实现 |
它可以有默认的方法实现 |
所有的方法都是抽象的。不存在方法的实现 |
实现 |
子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。 |
子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 |
抽象类有构造器,用于子类初始化 |
接口不能有构造器 |
普通类 |
除了不能实例化抽象类之外,它和普通Java类没有任何区别 |
接口是完全不同的类型 |
访问修饰符 |
抽象方法可以有public、protected和default这些修饰符 |
接口方法默认修饰符是public。不可以使用其它修饰符。 |
main方法 |
抽象方法可以有main方法并且我们可以运行它 |
接口没有main方法,因此我们不能运行它。 |
多继承 |
抽象方法可以继承一个类和实现多个接口 |
接口只可以继承一个或多个其它接口 |
速度 |
它比接口速度要快 |
接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 |
如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 |
如果你往接口中添加方法,那么你必须改变实现该接口的类。 |
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 "是不是"的关系,而 接口 实现则是 "有没有"的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。
设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。
Java异常处理的目的是提高程序的健壮性。你可以在catch和finally代码块中给程序一个修正机会,使得程序不因不可控制的异常而影响程序的流程。同时,通过获取Java异常信息,也为程序的开发维护提供了方便。
RuntimeException类及其子类都被称为运行时异常,这种异常的特点是Java编译器不去检查它,也就是说,当程序中可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws字句声明抛出它,还是会编译通过。
除了RuntimeException类及其子类外,其他的Exception类及其子类都属于受检查异常,这种异常的特点是要么用try...catch捕获处理,要么用throws语句声明抛出,否则编译不会通过。
运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误的操作。
受检查异常表示程序可以处理的异常。受检查异常表示程序可以处理的异常。如果抛出异常的方法本身不处理或者不能处理它,那么方法的调用者就必须去处理该异常,否则调用会出错,连编译也无法通过。
当然,这两种异常都是可以通过程序来捕获并处理的,比如除数为零的运行时异常。
异常处理机制为:抛出异常,捕捉异常。
import java.util.InputMismatchException; import java.util.Scanner;
public class TryCatch { public static void main(String[] args) { Scanner input = new Scanner(System.in);
try {// 可能会发生异常的程序代码 System.out.print("请输入一个数字:"); int a = input.nextInt(); } catch (InputMismatchException e) {// 捕捉异常 System.err.println("数据类型不符!"); e.printStackTrace(); System.err.println(e.getMessage()); // return; 若捕捉到异常会先执行finally, 再return。 } catch (Exception e) {// catch 先写子类,再写父类 System.out.println("再捕捉一次!"); System.exit(1); } finally {// 除非执行System.exit(1),否则都会执行 System.out.println("finally 被执行!"); // 应用举例:确保关闭数据库,关闭流 }
System.out.println("我还是被执行了!"); // 如果提前return,则不执行了 } } |
public class Throws {
public static void main(String[] args) throws Exception{ System.out.println(10 / 0); throw new Exception("抛出异常"); //System.out.println("throw后面的代码不再执行"); } } |
数组索引越界异常。当对数组的索引值为负数或大于等于数组大小时抛出。
算术条件异常。譬如:整数除零等。
空指针异常。当应用试图在要求使用对象的地方使用了null时,抛出该异常。譬如:调用null对象的实例方法、访问null对象的属性、计算null对象的长度、使用throw语句抛出null等等
找不到类异常。当应用试图根据字符串形式的类名构造类,而在遍历CLASSPAH之后找不到对应名称的class文件时,抛出该异常。
待补充~
如果出现异常的线程为主线程,则整个程序运行终止;如果非主线程,则终止该线程,其他线程继续运行。
如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆盖的方法中出现了异常,只能try不能throws。
如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过throw抛出RuntimeException异常或者其子类,这样,子类的方法上是不需要throws声明的。
越早处理异常消耗的资源和时间越小,产生影响的范围也越小。
大多集合能够处理任何类型的数据,因为这些集合定义的处理对象使用了Object类型。
所有的Java集合都在java.util包中。
上述类图中,实线边框的是实现类,比如ArrayList,LinkedList,HashMap等,折线边框的是抽象类,比如AbstractCollection,AbstractList,AbstractMap等,而点线边框的是接口,比如Collection,Iterator,List等。 |
Java 集合框架 |
|||||
接口 |
实现类 |
是否有序 |
是否允许元素重复 |
特点 |
|
Collection |
Collection |
无序 |
不唯一 |
父接口 |
|
List |
ArraysList |
有序 |
不唯一 |
遍历访问效率高[Z1] |
|
LinkedList |
有序 |
不唯一 |
插入删除效率高 |
||
Set |
AbstractSet |
无序 |
唯一 |
|
|
HashSet |
查找效率高 |
||||
Map |
TreeSet |
二叉排序树 |
key必须唯一 |
|
|
AbstractMap |
否 |
|
|||
HashMap |
查询指定元素效率高 |
||||
TreeMap |
二叉排序树 |
|
返回类型 |
方法 |
解释 |
boolean |
add(E e) |
确保此 collection 包含指定的元素(可选操作)。 |
void |
clear() |
移除此 collection 中的所有元素(可选操作)。 |
boolean |
contains(Object o) |
如果此 collection 包含指定的元素,则返回 true。 |
boolean |
isEmpty() |
如果此 collection 不包含元素,则返回 true。 |
boolean |
remove(Object o) |
从此 collection 中移除指定元素的单个实例。 |
int |
size() |
返回此 collection 中的元素数。 |
boolean |
equals(Object o) |
比较此 collection 与指定对象是否相等。 |
Object[] |
toArray() |
返回包含此 collection 中所有元素的数组。 |
Iterator<E> |
iterator() |
返回在此 collection 的元素上的迭代器 (接口)。 |
Ps:1.传入均为形参,不须类型修饰。2.接口不可实例化。方法全部交由实现类实现。
class Arrays { // 除特殊表明,为 Collection接口所有实现类所的方法 ArrayList<String> list = new ArrayList<String>();
void OwMethod() { list.add("且听风吟_z"); list.add("山多拉之灯"); list.add(0, "Jake"); // 使用下标确定添加位置
System.out.println(list.get(1)); // list 特有 System.out.println("下标为:" + list.indexOf("Jake")); // list 特有 System.out.println(list.set(0, "Captain")); // 替换元素, list 特有 System.out.println("判断包含元素:" + list.contains("Captain"));
System.out.println("该集合有元素数:" + list.size()); System.out.println("移除元素:" + list.remove("山多拉之灯"));
System.out.println("字符串型式返回元素:" + list.toString()); System.out.println("这是什么鬼:" + list.toArray() + "\n");
list.clear(); // 没有返回值 System.out.println("\n判断是否为空:" + list.isEmpty()); } } |
Ps:注意元素时对象时的区别
<E> |
get(int index) |
返回列表中指定位置的元素。 |
<E> |
set(int index, E element) |
用指定元素替换列表中指定位置的元素(可选操作)。 |
<E> |
getFirst() |
返回此列表的第一个元素。 |
<E> |
getLast() |
返回此列表的最后一个元素。 |
<E> |
removeFirst() |
移除并返回此列表的第一个元素。 |
class Link { // LinkedList 方法举例
LinkedList<String> list2 = new LinkedList<String>();
void OwMethod() { list2.add("No.1"); list2.addFirst("我是第一个!"); list2.add("No.2");
System.out.println("LinkedList 返回元素:" + list2.getFirst()); list2.removeFirst(); System.out.println("LinkedList 返回元素:" + list2.toString()); } } |
Link补充:1. 删除元素后,index后面的元素会自动向前补齐
2.索引若没有元素,返回-1。
class Set { // HashSet 方法举例 HashSet<String> list6 = new HashSet<String>();
void OwMethod() { list6.add("cat"); list6.add("dog"); System.out.println(list6.getClass()); } } |
返回类型 |
方法 |
解释 |
boolean |
containsKey(Object key) |
确保此 collection 包含指定的元素。 |
<V> |
get(Object key) |
返回指定键所映射的值。 |
<V> |
put(K key, V value) |
将指定的值与此映射中的指定键关联。 |
Collection<V> |
values() |
返回此映射中包含的值的 Collection集合。 |
Set<K> |
keySet() |
返回此映射中所包含的键的 Set集合。 |
class Map { HashMap<Integer, String> list7 = new HashMap<Integer, String>(); // Map要得是对象,不能放int void OwMethod() {
list7.put(1, "car"); // key 不可以重复 list7.put(2, "truck"); // Value 的值可以是普通数据也可以是对象 list7.put(3, "bus"); System.out.println("是否包含key = 1:" + list7.containsKey(1)); System.out.println("key所对应的值:" + list7.get(1)); System.out.println("包含Value的所有元素:" + list7.values()); System.out.println("包含Key的所有元素:" + list7.keySet());
System.out.println("HashMap返回元素:" + list7.toString() + "\n"); } } |
boolean |
hasNext() |
如果仍有元素可以迭代,则返回 true。 |
Set<K> |
next() |
返回迭代的下一个元素。 |
void |
remove() |
移除迭代器返回的最后一个元素。 |
补充:遍历集合元素的几种方法
Collections.sort(list); // Ps:不是必须的 Iterator<String> iter = list.iterator(); //1.调用迭代器,遍历集合元素 while (iter.hasNext()) { String name = iter.next(); System.out.println(name); }
for (String str : list) { // 2.使用增强for循环,遍历集合元素 System.out.println(str); } // 3.转换成字符串,遍历集合元素 System.out.println("HashMap返回元素:" + list.toString() + "\n"); |
Java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
Void |
sort(List<T> list) |
根据自然顺序 对指定列表按升序进行排序。 |
<T> |
Max |
根据自然顺序,返回给定 collection 的最大元素。 |
<T> |
Min |
根据自然顺序,返回给定 collection 的最小元素。 |
<T> |
Max (Comparator) |
重写比较器,返回给定 collection 的最大元素。 |
<T> |
Fill(list,obj) |
使用指定元素替换指定列表中的所有元素。 |
<T> |
binarySearch |
使用二分搜索法搜索指定列表,以获得指定对象。 |
注:<T>的正式名称为类型参数,也可通俗的称为占位符,符号读作of T。
Collections.sort(list); Iterator<Student> it = list.iterator(); while (it.hasNext()) { Student stu = (Student) it.next(); System.out.println(stu.getNumber()); }
int index = Collections.binarySearch(list, student1); System.out.println("student1的下标是:" + index);
Student stu1 = Collections.max(list); System.out.println("最大值的下标是:" + stu1.getNumber());
// Collections.fill(list, "我被替换了"); // 替换的是什么东西?? |
接口:public interface Comparable<T>
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)
public int compareTo(Object obj) { Student student = (Student) obj; if (this.number == student.number) { // 用对象还是get都可以 return 0; } else if (this.number > student.getNumber()) { return 1; } else { return -1; } } |
a) 注意API中参数是对象还是普通数据类型。
b) 集合中的元素可以是普通数据也可以是对象。
c) 泛型执行定义了类型,避免了装箱和拆箱操作,性能有很大提高了。详见 高级特性à包装类à装箱/拆箱。
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
为什么使用泛型? 先来看使用非泛型集合的两个问题:性能问题和类型安全问题。
性能问题:不管选择哪个类型来保存,都不能避免使用非泛型容器带来的装箱问题,所以提出了泛型。
类型安全问题:在泛型之前,要解决类型安全问题的唯一方法是手工创建自定义(强类型的)集合类。
API(Application Programming Interface)应用程序编程接口,它是运行库的集合,预先定义了一些借口和类。API 提供如下常用的包:
public enum Week { MON, TUE, WED, THU, FRI, SAT, SUN; } // 调用 Week. MON |
public enum FORMAT { YYYY_MM_DD_FORMAT("yyyy-MM-dd"), // 为枚举元素赋值先定义元素,再定义属性 DD_MM_YYYY_FORMAT("dd-mm-yyyy");
private String stringValue;
private FORMAT(String stringValue) { this.stringValue = stringValue; } public String getStringValue() { return stringValue; } } // 调用 FORMAT.DD_MM_YYYY_FORMAT.getStringValue() |
基本数据类型 |
包装类 |
包装类 |
包装类 |
byte |
Byte |
Number |
Object |
short |
Short |
||
int |
Integer |
||
long |
Long |
||
float |
Float |
||
double |
Double |
||
char |
Character |
|
|
boolean |
Boolean |
|
大多集合能够处理任何类型的数据,因为这些集合定义的处理对象使用了Object类型。当集合处理的数据是JAVA中的基本类型时,比如int、float、double类型,这些类型在JAVA中属于值类型,而这些数据进入集合中时,集合能够处理的是Object这样的引用类型,所以在值类型的数据进入集合的时候,需要将值类型包装成引用类型,这个过程就是装箱的过程,从集合中取出数据时,取出的是引用类型,同样需要把引用类型还原为值类型,这个过程就是拆箱的过程。
Integer num1 = new Integer(123); // 手动装箱方式,构造方法 Integer num2 = new Integer("123"); // 除Character类外的基本类型 Character num3 = new Character(‘a‘); Integer num4 = Integer.valueOf(123); Integer num5 = 1; // 自动装箱 |
int num1_1 = num1.intValue(); // 手动拆箱方式 int num5_1 = num5; // 自动拆箱 |
String sex=Character.toString(‘男‘); // 基本类型->字符串 int num=Integer.parseInt("36"); // 字符串->基本类型 //可用于校验字符是否合法 sex=‘男‘+""; // 合并转换字符串的一种方式 |
//获取随机数的两种random()方法: int show1 = (int) (Math.random() * 5.0D) + 1; int show2 = (int) (Math.random() * 10.0D) % 5 + 1; System.out.println(Math.max(show1, show2)); System.out.println(Math.abs(-10)); // 绝对值运算 System.out.println(Math.E + "\n" + Math.PI); // 两个常量 //Ps:random()返回一个大于等于0小于1的随机数。 |
在Java中,字符串被作为String类型的对象来处理。String类位于java.lang包中。字符串是一个字符序列,事实上也是一个字符数组。可用下标索引。
String s1 = "-Java-"; String s1_1 = s1.toLowerCase(); // 转为小写 String s1_2 = s1.toUpperCase(); // 转为大写
String s2 = "渺千山暮雪,"; String s3 = "万里层云,"; String s4 = "只影向谁去?";
String s5 = s2.concat(s3.concat(s4)); // 连接字符串 String[] s6 = s5.split("。|,|?"); // 字符串拆分,用数组接收 String s7 = s5.substring(1, 5); // 提取下标区间字段
System.out.println(s1.equals(s1_2)); // 比较字符串,详见运算符章节 System.out.println(s1_1.equalsIgnoreCase(s1_2)); // 比较字符串,忽略大小写 System.out.println(s5); for (String temp : s6) { System.out.println(temp); } System.out.println(s7); // indexOf()查询若不存在返回index = -1 System.out.println(s7.length()); //字符串长度 System.out.println("第一次出现逗号位置的下标:" + s5.indexOf(",")); System.out.println("最后出现逗号位置的下标:" + s5.lastIndexOf(",")); |
StringBuffer s1 = new StringBuffer("仰天大笑出门去"); StringBuffer s2 = s1.append("无人知是荔枝来!");// 效率比concat()高 StringBuffer s3 = s2.insert(7, ","); // 返回StringBuffer,不能用String接收。 int s4 = s3.hashCode(); //StringBuffer 好多方法可以用 System.out.println(s3); System.out.println(s4); |
注释:StringBufffer类和StringBulider类处理字符串的方法基本一致。
Date date = new Date(); // 创建日期对象 SimpleDateFormat formater // HH表示24时制 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("当前时间为:" + formater.format(date));
Calendar t = Calendar.getInstance(); // 抽象类,得到子类对象 System.out.println("今天是" + t.get(Calendar.YEAR) + "年" + (t.get(Calendar.MONTH) + 1) + "月" + t.get(Calendar.DAY_OF_MONTH) + "日"); // Calendar.DAY_OF_WEEK 中 Sunday是 1 System.out.println("今天是星期" + (t.get(Calendar.DAY_OF_WEEK) - 1)); } |
Random rand = new Random(47); int show1 = rand.nextInt(10); //产生一个大于等于0,小于10的随机数 System.out.println(show1); //Math.random()方法底层是使用Random类实现的 |
@SuppressWarnings("static-access") public static void main(String[] args) throws IOException { SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
File file1 = new File("I:/myDoc"); // 创建新 File 实例,创建的是引用 file1.mkdir(); // 创建文件夹 file.mkdirs() file1.createTempFile("temp", ".txt", file1); // 创建临时文件 System.out.println("是目录:" + file1.isDirectory());
File file2 = new File("I:/myDoc/temp.txt"); // 可是文件,也可是目录 file2.createNewFile(); //创建文件 System.out.println("是文件:" + file2.isFile());
System.out.println("文件是否存在:" + file2.exists()); System.out.println("名称:" + file2.getName()); System.out.println("相对路径: " + file2.getPath()); System.out.println("绝对路径: " + file2.getAbsolutePath()); System.out.println("文件大小:" + file2.length() + " 字节"); System.out.println("最后修改日期: " + formater.format(file2.lastModified())); } System.out.println("文件是否删除:" + file2.delete()); |
流,是指一连串流动的字符,是以先进先出的方式发送和接收数据的通道。流分为输入和输出流。输入/输出时相对于内存来说的(往里读,往外写)。Java的输出流主要有OutputStream和White作为抽象基类,而输入流主要由InputStream和Reader作为抽象基类。
字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组。所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,所以它对多国语言支持性比较好。
如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。
所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成字节序列。
字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
字节流在操作的时候是直接与文件本身关联,不使用缓冲区,字节直接存到文件中;字符流在操作的时候是通过缓冲区与文件操作,字符到缓冲区然后再到文件中,所以字符流中存在一个flush()方法来刷新缓冲区。
//******** 问题:下列步骤数据存储和转换的过程是怎么样的? 编码:UTF-8 ******* // 1. 把一个字符串 "苏A" 输入缓冲区 (33487)10000010 11001111 (65)01000001 UTF-16 // 1. 在缓冲区加高位转换成UTF=8 11101000/10001011/10001111/01000001 // 2. 转换成byte[] //用长度为4的字节数组接受 Byte1 = 11101000 Byte2 = ... // 3 .然后存入文本 // 把四个字节数组存入文本(阅读文本时,解码器解码) // 4. 然后从文本读取 //把文档内容以字节(符)型式读入内存,并转换成char // 注:苏A == (\u82cf--16进制表达) ((232) 11101000 (139) 10001011 (143) 10001111) (65)01000001 // 如果不知道编码方式,可能同样的二进制数,解码方式有误,导致解码失败。 // IO操作的是序号,通过字库表,对应显示正确的字符。 public class Keep_Stream_Test {
public static void main(String[] args) throws IOException {
int date, temp; String line; String str = "苏A"; //UTF-8 汉字一个字符约三个字节 char a = ‘C‘; // 一个整型代表一个字符,故可以互相转换 byte[] words = str.getBytes(); // 把字符串内容写进字节数组 System.out.println(System.getProperty("file.encoding")); // 获得本地平台的字符编码类型 /** * 字节流写入数据 * */ FileOutputStream fos1 = new FileOutputStream("I:/text1.txt"); fos1.write(552); // 读写的是序号 // 往里读,往外写 // 非正确演示 fos1.write(words, 0, words.length);// 把字节数组存储的内容写进流 /** * 字符流写入数据 * */ FileWriter fw = new FileWriter("I:/text1.txt", true);//不覆盖原文件 BufferedWriter bw = new BufferedWriter(fw); // 装饰者模式 bw.write("-南京"); bw.write(‘)‘); bw.flush(); // 往外写时才用 /** * 字节流读取数据 * */ FileInputStream fis1 = new FileInputStream("I:/text1.txt"); BufferedInputStream bis1 = new BufferedInputStream(fis1); System.out.println("文件大小:" + bis1.available() + "字节\n"); while ((date = fis1.read()) != -1) { // 把文本内容以字节型式读入内存 System.out.print(date); System.out.print((char) date); System.out.println("\t" + Integer.toBinaryString(date)); } // 此处对应关系与编码方式有关,多字节解码方式有误 // 没有缓冲区,读一个字节,转一个。so如果汉字是单字节就不会出错鸟~ System.out.println(‘\n‘); /** * 字符流读取数据 * */ FileReader fr1 = new FileReader("I:/text1.txt"); BufferedReader br1 = new BufferedReader(fr1); while ((date = br1.read()) != -1) { // 把文档内容以字符型式读入内存 System.out.print(date); System.out.print((char) date); System.out.println("\t" + Integer.toBinaryString(date)); } while ((line = br1.readLine()) != null) { // 把文档内容以字符型式(每次一行)读入内存,返回字符串。这一段读不出流 只可用一次。 System.out.print(line); // 由于字符流有缓冲区,所以2个字符读(Unicode)与一行行读都可以,最终按 编码方式处理。 } /** * 字符流读取数据 InputStreamReader 是字节流通向字符流的桥梁 * */ InputStreamReader isr = new InputStreamReader(fis1, "UTF-8"); // 转换流 BufferedReader br2 = new BufferedReader(isr);// 缓冲流 while ((temp = br2.read()) != -1) { System.out.print((char) temp); // 流使用一次就不能再用了?? } System.out.println(‘\u82cf‘);// 十六进制表示一个字符 System.out.println((byte) a); } } |
u 缓冲流:缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能。
2 字节缓冲流有BufferedInputStream/ BufferedOutputStream,字符缓冲流有BufferedReader/BufferedWriter,字符缓冲流分别提供了读取和写入一行的方法ReadLine和NewLine方法。使用字符缓冲流的时候,一定先flush,再close。
u 转换流:用于字节数据到字符数据之间的转换。
2 字符流InputStreamReader/OutputStreamWriter。其中,InputStreamReader需要与InputStream“套接”,OutputStreamWriter要与OutputStream“套接”。
u 数据流:提供了读写Java中的基本数据类型的功能。
2 DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,须“套接”在InputStream和OutputStream类型的节点流上。
u 对象流:用于直接将对象写入写出。
2 对象流类有ObjectInputStream和ObjectOutputStream,本身这两个方法没什么,但是其要写出的对象有要求,该对象必须实现Serializable接口,来声明其是可以序列化的。否则,不能用对象流读写。
u 还有一个关键字比较重要,transient,由于修饰实现了Serializable接口的类内的属性,被该修饰符修饰的属性,在以对象流的方式输出的时候,该字段会被忽略。
两个类的构造方法的形式和参数都是相同的,参数为File对象或表示路径的String。
FileInputStream以字节流方式读取,FileReader把文件转换为字符流读入。
PrintWriter提供的print/println/printf等方法方便使用,并封装了字节流与字符流之间的转换。BufferedWriter提供缓冲。详见TCP编程章节例程。
File流以文件作为参数,处理流以节点流或其子类作为参数。
Java输入、输入、IO流 类层次关系梳理 http://www.cnblogs.com/LittleHann/p/3678685.html
/** * 二进制文件读取操作 * */ FileInputStream fis3 = new FileInputStream("I:/text1.txt"); DataInputStream dis1 = new DataInputStream(fis3); /** * 二进制文件写入操作 * */ FileOutputStream fos2 = new FileOutputStream("I:/text2.txt"); DataOutputStream dos1 = new DataOutputStream(fos2); int temp2; while ((temp2 = dis1.read()) != -1) { // 读取文件并写入文件 dos1.write(temp2); } dos1.writeUTF("Hello"); // 将一个字符串写入文件 dos1.flush(); |
Java的标准输入/输出分别通过System.in和System.out来代表,在默认的情况下分别代表键盘和显示器,当程序通过System.in来获得输入时,实际上是通过键盘获得输入。当程序通过System.out执行输出时,程序总是输出到屏幕。
/** * System.out 重定向向文件输出 * */ PrintStream ps = new PrintStream(new FileOutputStream("work")); System.setOut(ps); System.out.println("Hello World!"); /** * System.in 重定向从文件输入 * */ FileInputStream fis = new FileInputStream("work"); System.setIn(fis);
Scanner sc = new Scanner(System.in); while (sc.hasNextLine()) { System.out.println(sc.nextLine()); } |
序列化是将对象的状态写入到特定的流中的过程,反序列化则是从特定的流中获取数据重新构建对象的过程。
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c:\\myDoc\\stu.txt")); Student stu = new Student("安娜", 30, "女"); // 对象序列化 oos.writeObject(stu);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream( "c:\\myDoc\\stu.txt")); // 对象反序列化 Student stu1 = (Student) ois.readObject(); System.out.println("姓名为:" + stu1.getName()); System.out.println("年龄为:" + stu1.getAge()); System.out.println("性别为:" + stu1.getGender()); Ps:class Student implements java.io.Serializable |
补充:静态数据不能被序列化,因为静态数据不在堆内存中,是存储在静态方法区中。用transient 关键字修饰非静态数据也不会被序列化。
其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。反射技术大大的增强了程序的扩展性。
参考资料:
我们在计算机屏幕上看到的是实体化的文字,而在计算机存储介质中存放的实际是二进制的比特流。那么在这两者之间的转换规则就需要一个统一的标准。
字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。均占一个字符,但字节长度由于编码方式的不同而不同。
字符集(Charset):是字符的集合。常见字符集有:ASCII字符集、ISO-8859-1字符集(兼容ASCII) 、GB2312字符集(兼容ASCII) 、GBK字符集(兼容GB2312)、BIG5字符集、GB18030字符集(兼容GBK)、Unicode(兼容ISO-8859-1)字符集等。
字符不一定适合作传输、储存等处理,有时须经编码(encode)后才能应用。如Unicode(UTF-8、UTF-16、UTF-32)、GBK等方式编码。
对于一个字符集来说要正确编码转码一个字符需要三个关键元素:字库表(character repertoire)、编码值(coded character set)、字符编码(character encoding form)。其中字库表是一个相当于所有可读或者可显示字符的数据库,字库表决定了整个字符集能够展现表示的所有字符的范围。用一个编码值(数值代码)来对应字库中的每一个字符。字符编码,将编码值(数值代码)以一定编码方式转化成二进制数,以便与进行传输、储存等处理。过程:字符à编码值à二进制值。
苏A 的 存 储 形 式 为 : ASCII 码: (33487) 10000010 11001111 (65) 01000001 UTF-8: (\u82cf)( (232) 11101000 (139) 10001011 (143) 10001111) (65) 01000001 |
符号:英文标点占一个字节,全角两个字节。中文标点占两个字节,全角四个字节。
参考文章:十分钟搞清字符集和字符编码,字符集和字符编码(Charset & Encoding)
所有的文件在内存和磁盘中都是二进制格式的,所以文本文件与二进制文件的区别并不是物理上的,而是逻辑上的。这两者只是在编码层次上有差异。
文本文件是基于字符编码的文件,常见的编码有ASCII(双字节字符集)、Unicode(可变字节字符集)编码等。二进制文件是基于值编码的文件,二进制读取只可正对二进制文件。
用ASCII方式处理文件,一个字节(8 Bite)放一个ASCII字符,因而便于对字符进行逐个处理,也便于输出字符,但一般占储空间较多,而且要花费较多的转换时间。二进制文件是把内存中的数据按其在内存中的存储形式原样输出到磁盘上存放,用二进制形式输出数值,可以节省外存空间和转换时间。
文本文件的读取需要按照相应的编码方式进行解码。
5678 的 存 储 形 式 为 : ASCII 码: 00110101 00110110 00110111 00111000 (四个字节) 二进制: 00010110 00101110 (两个字节) |
注释:ASCII码是8 Bite的编码,Unicode码元一般占16 Bite。
待补充~
注解一种标记
Annotation //注解
@Deprecated
@SuppressWarnings("deprecation") 消除警告
@Override 重写
自定义注解
比如A注解
public @interface A {
}
元注解
@Retention
@Target
待补充~
进程:正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间。
线程:其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。线程负责的是应用程序的执行顺序。
public class Thread_Demo {
public static void main(String[] args) { Demo1 d1 = new Demo1(); // Runnable实现类,只有run()方法 Thread t = new Thread(d1); // Thread对象调用start()方法 t.start();
Demo2 d2 = new Demo2(); d2.start(); //Thread对象调用start()方法 } }
class Demo1 implements Runnable { // 实现Runnable接口方式实现多线程
public void run() { System.out.println("Runnable"); } }
class Demo2 extends Thread { // 继承Thread类实现多线程 public void run() { System.out.println("Thread"); } |
运行状态(Running):就绪状态的线程获取了CPU,执行程序代码。
u 等待阻塞:运行的线程执行wait()方法,JVM会把该线程放入等待池中。
u 同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
u 其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完,另一个线程参与进来执行,导致共享数据的错误。
解决办法:对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其他线程不执行。
同步代码块: public class ThreadDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t, "窗口一"); Thread t2 = new Thread(t, "窗口二"); Thread t3 = new Thread(t, "窗口三"); Thread t4 = new Thread(t, "窗口四"); t1.start(); t2.start(); t3.start(); t4.start(); } }
class Ticket implements Runnable { private int ticket = 100;
public void run() { while (true) { synchronized (new Object()) { // synchronized关键字,用来修饰方法或代码块的时,保证同时最多只有一个线程执行 该段代码。 if (ticket <= 0) break; System.out.println(Thread.currentThread().getName() + "---卖出"+ ticket--); } } } } |
同步函数: public class ThreadDemo { public static void main(String[] args) { Ticket t = new Ticket(); Thread t1 = new Thread(t, "窗口一"); Thread t2 = new Thread(t, "窗口二"); Thread t3 = new Thread(t, "窗口三"); Thread t4 = new Thread(t, "窗口四"); t1.start(); t2.start(); t3.start(); t4.start(); } }
class Ticket implements Runnable { private int ticket = 100;
public synchronized void saleTicket() { if (ticket > 0) System.out.println(Thread.currentThread().getName() + "卖出了" + ticket--); }
public void run() { while (true) { saleTicket(); } } } |
等待唤醒机制: |
生产消费机制: |
参考资料:
网络编程的目的就是指直接或间接地通过网络协议与其他计算机进行通讯。网络编程中有两个主要的问题,一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输。在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可以唯一地确定Internet上的一台主机。而TCP层则提供面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象,一般不需要关心IP层是如何处理数据的。
目前较为流行的网络编程模型是客户机/服务器(C/S)结构。
是目前世界上应用最为广泛的协议,是以TCP和IP为基础的不同层次上多个协议的集合,也成TCP/IP协议族、或TCP/IP协议栈
IP网络中每台主机都必须有一个唯一的IP地址,IP地址是一个逻辑地址。
为进行网络中的数据交换(通信)而建立的规则、标准或约定。(=语义+语法+规则)。
不同层具有各自不同的协议。
IP地址用来标识网络上的计算机,而端口号用来指明该计算机上的应用程序。
一台计算机要发送数据到另一台计算机,数据首先必须打包,打包的过程称为封装。
封装就是在数据前面加上特定的协议头部。
网络上具有唯一标识的IP地址和端口组合在一起才能构成唯一能识别的标识符套接字。
u 通信的两端都有Socket。
u 网络通信其实就是Socket间的通信。
u 数据在两个Socket间通过IO传输。
针对网络通信的不同层次,Java提供了不同的API,其提供的网络功能有四大类:
// 使用域名创建对象 InetAddress inet1 = InetAddress.getByName("www.163.com"); System.out.println(inet1); // 使用IP创建对象 InetAddress inet2 = InetAddress.getByName("127.0.0.1"); // 127.0.0.1是一个回送地址,指本地机,一般用来测试使用 System.out.println(inet2); // 获得本机地址对象 InetAddress inet3 = InetAddress.getLocalHost(); System.out.println(inet3); // 获得对象中存储的域名 String host = inet3.getHostName(); System.out.println("域名:" + host); // 获得对象中存储的IP String ip = inet3.getHostAddress(); System.out.println("IP:" + ip); |
// 创建一个URL的实例 URL baidu = new URL("http://www.baidu.com"); URL url = new URL(baidu, "/index.html?username=tom#test"); // ?表示参数,#表示锚点 System.out.println(url.getProtocol()); // 获取协议 System.out.println(url.getHost()); // 获取主机 System.out.println(url.getPort()); // 如果没有指定端口号,根据协议不同使用默认端口。getPort()方法的返回值为 -1 System.out.println(url.getPath()); // 获取文件路径 System.out.println(url.getFile()); // 文件名,包括文件路径+参数 System.out.println(url.getRef()); // 相对路径,就是锚点,即#号后面的内容 System.out.println(url.getQuery()); // 查询字符串,即参数 |
URL url_2 = new URL("http://www.baidu.com"); InputStream is = (InputStream) url_2.openStream(); // 通过openStream方法获取资源的字节输入流 InputStreamReader isr = new InputStreamReader(is, "UTF-8"); // 将字节输入流转换为字符输入流,如果不指定编码,中文可能会出现乱码 BufferedReader br = new BufferedReader(isr); // 为字符输入流添加缓冲,提高读取效率 String data = br.readLine();// 读取数据 while (data != null) { System.out.println(data);// 输出数据 data = br.readLine(); } br.close(); isr.close(); is.close(); |
TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低。
|
① 创建ServerSocket和Socket
② 打开连接到Socket的输入/输出流
③ 按照协议对Socket进行读/写操作
④ 关闭输入输出流、关闭Socket
① 创建ServerSocket对象,绑定监听端口
② 通过accept()方法监听客户端请求
③ 连接建立后,通过输入流读取客户端发送的请求信息
④ 通过输出流向客户端发送乡音信息
⑤ 关闭相关资源
public class DemoTCP_Server { public static void main(String[] args) throws IOException { /** * 基于TCP协议的Socket通信,实现用户登录,服务端 */ // 1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket serverSocket = new ServerSocket(10086); // 2、调用accept()方法开始监听,等待客户端的连接 Socket socket = serverSocket.accept(); // 3、getInputStream()方法获取输入流,并读取客户端信息 InputStream is = socket.getInputStream(); // 返回InputStream InputStreamReader isr = new InputStreamReader(is); // 转化流处理 BufferedReader br = new BufferedReader(isr); String info = null; while ((info = br.readLine()) != null) { System.out.println("我是服务器,客户端说:" + info); } socket.shutdownInput(); // 关闭输入流 // 4、获取输出流,响应客户端的请求 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("欢迎您!"); pw.flush();
// 5、关闭资源,注意顺序 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close(); } } |
① 创建Socket对象,指明需要连接的服务器的地址和端口号
② 连接建立后,通过输出流想服务器端发送请求信息
③ 通过输入流获取服务器响应的信息
④ 关闭响应资源
public class DemoTCP_Clinet { // 客户端 public static void main(String[] args) throws IOException {
// 1、创建客户端Socket,指定服务器地址和端口 Socket socket = new Socket("localhost", 10086); // 2、获取输出流,向服务器端发送信息 OutputStream os = socket.getOutputStream();// 字节输出流 PrintWriter pw = new PrintWriter(os);// 将输出流包装成打印流 pw.write("用户名:admin;密码:123"); pw.flush(); socket.shutdownOutput(); // 关闭客户端的输出流。相当于给流中加入一个结束标记-1 // 3、获取输入流,并接收服务器端的反馈信息 InputStream is = socket.getInputStream(); // BufferedReader br = new BufferedReader(new InputStreamReader(is)); Scanner input = new Scanner(new InputStreamReader(is)); while (input.hasNextLine()) { //用Scanner接收输入流,对比服务端方法优劣 System.out.println("我是客户端,服务器说:" + input.nextLine()); }
// 4、关闭资源 input.close(); is.close(); pw.close(); os.close(); socket.close(); } } |
PrintWriter作为一个便捷的字节流与字符流之间的转换工具,已经封装了转换的方法,直接使用它回写的时候,不用再使用getBytes()转换成字节流。
如用byte数组接收,将得到的字节流写入数组后,得把它转化为一个String的对象(用String(数组名,第一个索引,长度))。
如用缓冲流接收时,需要用InputStreamReader转化。综合来说,还是PrintWriter比较方便。
shutdownInput():关闭Socket的输入流,程序还可以通过该Socket的输出流输出数据。
客户端连接到服务器后,开始发送数据,发送完成后无须再次发送数据,只需要读取服务器响应数据即可,当读取响应完成后,该Socket连接也被关闭了。
Scanner接收InputSteam对象,调用nextLine()方法读取流文件。
① 服务器端创建ServerSocket,循环调用accept()等待客户端连接
② 客户端创建一个socket并请求和服务器端连接
③ 服务器端接受客户端请求,创建socket与该客户建立专线连接
④ 建立连接的两个socket在一个单独的线程上对话
⑤ 服务器端继续等待新的连接
public class DemoThread_Clinet { // 客户端 public static void main(String[] args) throws IOException { Socket socket = new Socket("localhost",10086); socket.close(); } } |
public class DemoThread_Server extends Thread {// 服务器端 Socket socket = null; public DemoThread_Server(Socket socket) { // 以Sockeet为参的构造方法 this.socket = socket; }
public void run() { }
public static void main(String[] args) throws IOException { ServerSocket serverSocket = new ServerSocket(10086); Socket socket = null; int count = 0;// 记录客户端的数量 while (true) { socket = serverSocket.accept(); // 阻塞状态,接收客户端请求,然后往下执行,新增线程 DemoThread_Server serverThread = new DemoThread_Server(socket); serverThread.start(); count++; System.out.println("客户端连接的数量:" + count); } } } |
UDP协议(用户数据报协议)是无连接的、不可靠的、无序的,速度快。进行数据传输时,首先将要传输的数据定义成数据报(Datagram),大小限制在64k,在数据报中指明数据索要达到的Socket(主机地址和端口号),然后再将数据报发送出去。
① 创建DatagramSocket,指定端口号
② 创建DatagramPacket
③ 接受客户端发送的数据信息
④ 读取数据
public class DemoUDP_Server { /** * 服务器端,实现基于UDP的用户登录 * */ public static void main(String[] args) throws IOException {
// 1、创建服务器端DatagramSocket,指定端口 DatagramSocket socket = new DatagramSocket(8888); // 2、创建数据报,用于接受客户端发送的数据 byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length); // 3、接受客户端发送的数据 socket.receive(packet);// 此方法在接受数据报之前会一直阻塞 // 4、读取数据 String info = new String(data, 0, data.length); System.out.println("我是服务器,客户端告诉我" + info);
// 1、定义客户端的地址、端口号、数据 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] data2 = "欢迎您!".getBytes(); // 2、创建数据包,包含响应的数据信息 DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port); // 3、响应客户端` socket.send(packet2); // 4、关闭资源 socket.close(); } } |
① 定义发送信息
② 创建DatagramPacket,包含将要发送的信息
③ 创建DatagramSocket
④ 发送数据
public class DemoUDP_Clinet { // 客户端
public static void main(String[] args) throws IOException {
// 1、定义服务器的地址、端口号、数据 InetAddress address = InetAddress.getByName("localhost"); int port = 8888; byte[] data = "用户名:admin;密码:123".getBytes(); // 2、封包,包含发送的数据信息 DatagramPacket packet = new DatagramPacket(data, data.length, address, port); // 3、创建DatagramSocket对象 DatagramSocket socket = new DatagramSocket(); // 4、向服务器发包 socket.send(packet);
// 1、创建数据包,用于接受服务器端响应数据 byte[] data2 = new byte[1024]; DatagramPacket packet2 = new DatagramPacket(data2, data2.length); // 2、接受服务器响应的数据 socket.receive(packet2); String reply = new String(data2, 0, packet2.getLength()); System.out.println("我是客户端,服务器说:" + reply); // 4、关闭资源 socket.close(); } } |
参考资料:
<?xml version = "1.0" encoding="UTF-8"?> <PhoneInfo> <Brand name="华为"> <Type name="U8650"></Type> <Type name="HW123"></Type> <Type name="HW321"></Type> </Brand> <Brand name="苹果"> <Type name="Iphone5"></Type> <Type name="Iphone6"></Type> <Type name="Iphone6s"></Type> </Brand> </PhoneInfo> |
public class ParseXMLDemo { // Document、NoteList、Note、Element 接口 private Document document;
public static void main(String[] args) throws Exception { ParseXMLDemo pd = new ParseXMLDemo(); pd.getDocument(); pd.showInfo(); System.out.println("------------------"); pd.add(); pd.delete(); pd.update(); pd.showInfo(); pd.saveXML("E:/JAVA/U1/U2-1/src/chapter06/new.xml"); }
public void getDocument() throws Exception { // 获得DOM树 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse("E:/JAVA/U1/U2-1/src/chapter06/XMLDemo.xml"); // 1、创建解析器工厂 2、创建解析器 3、操作xml对象 }
public void showInfo() {// 获取手机品牌和属性 NodeList brands = document.getElementsByTagName("Brand"); for (int i = 0; i < brands.getLength(); i++) { Node node = brands.item(i); Element eleBrand = (Element) node;// 节点强转元素 System.out.println(eleBrand.getAttribute("name"));
NodeList types = node.getChildNodes(); for (int j = 1; j < types.getLength(); j++) { Node typeNode = types.item(j); if (typeNode.getNodeType() == node.ELEMENT_NODE) {//元素节点 Element eleType = (Element) typeNode; System.out.println("\t" + eleType.getAttribute("name")); } } } }
public void saveXML(String path) throws Exception { TransformerFactory factory = TransformerFactory.newInstance(); factory.setAttribute("indent-number", "4");// 设置缩进 Transformer transformer = factory.newTransformer(); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");//转换器 transformer.setOutputProperty(OutputKeys.INDENT, "yes");//开启缩进 // StreamResult result=new StreamResult(new FileOutputStream(path)); DOMSource source = new DOMSource(document);// 设置源 StreamResult result = new StreamResult(new OutputStreamWriter( new FileOutputStream(path), "UTF-8"));// 设置目标 transformer.transform(source, result);// 转换 }
public void add() throws Exception {// 添加 Element element1 = document.createElement("Brand"); element1.setAttribute("name", "三星"); Element element2 = document.createElement("Type"); element2.setAttribute("name", "Note3"); element1.appendChild(element2); document.getElementsByTagName("PhoneInfo").item(0) .appendChild(element1); this.saveXML("E:/JAVA/U1/U2-1/src/chapter06/new.xml"); }
public void update() throws Exception {// 修改 NodeList brands = document.getElementsByTagName("Brand"); for (int i = 0; i < brands.getLength(); i++) { Node brand = brands.item(i); Element eleBrand = (Element) brand; // 修改的是元素的属性 eleBrand.setAttribute("id", i + ""); // i转为String this.saveXML("E:/JAVA/U1/U2-1/src/chapter06/new.xml"); } }
public void delete() throws Exception {// 删除 NodeList brands = document.getElementsByTagName("Brand"); for (int i = 0; i < brands.getLength(); i++) { Node brand = brands.item(i); Element eleBrand = (Element) brand; if ("华为".equals(eleBrand.getAttribute("name"))) { eleBrand.getParentNode().removeChild(eleBrand); } this.saveXML("E:/JAVA/U1/U2-1/src/chapter06/new.xml"); } } } |
|
在内存中分配连续的空间,
遍历访问效率高,但是在添加和删除
非尾部元素时会导致后面的所有元素的移动,
导致需要重新判断后面元素的下标,
这就造成ArrayList对插入、删除、等操作性能低下。
标签:方式 sock 另一个 抽象方法 端口 protect edit lower 水平
原文地址:http://www.cnblogs.com/bugdeaitaigaoshang/p/6881752.html