标签:
classpath
.;%java_home%\lib;%java_home%\lib\tools.jar;D:\Java\;
java_home
D:\Program Files\Java\jdk1.8.0_51
path
C:\Users\BaseKing-Sunie\AppData\Local\Code\bin;%java_home%\bin;%java_home%\jre\bin;
D:\adt-bundle-windows-x86_64_20131020\sdk\tools;D:\adt-bundle-windows-x86_64_20131020\sdk\platform-tools;
TEMP
%USERPROFILE%\AppData\Local\Temp
TMP
%USERPROFILE%\AppData\Local\Temp
第一本书
【Run As】
发现程序有问题,程序无法运行,但没有错误时,可以右键,然后移到Run As,如果显示是Run Configurations,而不是Java Application,则你的主函数可能错了。
【Scanner】类
扫描仪
scan 扫描
【println】
输出信息 换行打印
System.out.println(“”); 在控制台输出
[scan.nextDouble();]
double pay=scan.nextDouble();这句程序中,只有在你用键盘输入一个double型的数字后才会开始运行这句程序之后的程序。重点是scan.nextDouble();只针对这个。
[&]
Java变量只能包含数字、字母、下划线和$,而&不能在变量命名中使用,因此会出现编译错误
int &size=20; //用&是错误的
System.out.println(&size);
[jvm]
uitec/Common/binary/com.sun.java.jdk.linux.x86_1.6.0.013/lib/visualvm/visualvm/modules
【默认】
int共有10位数,long有19位数。
除了通常的十进制数字形式,整数直接量也可以写成16进制的形式(以0X或0x开头)或8进制的形式(以0开头),请看如下直接量三种表现形式:
int a = 100000; // 10进制
int b = 0x186a0; // 16进制
int c = 0303240; // 8进制
如果要表示long直接量,需要以 L 或 l 结尾。默认的是整形直接量int。示例代码如下:
long a = 10000000000; //会有编译错误,因为10000000000编译器认为是int类型,而这个值,已经超出了int的范围
long b = 10000000000l; //正确
默认的浮点直接量为double型,如果需要表示float类型的直接量,需要加“f”或“F”后缀。例如:
float f1 = 3.14 //编译错误,应该写成3.14f
[+]
int a = 1, b = 10;
int c1 = a++;
int c2 = ++b;
System.out.println("a=" + a + ", b=" + b + ", c1=" + c1 + ", c2=" + c2);
程序运行出来的结果
a=2, b=11, c1=1, c2=11
[计时操作]时间
JDK提供 System.currentTimeMillis() 方法,返回1970年1月1日零点到此时此刻所经历的毫秒数,数据太大,故其数据类型为long。示例代码如下:
long time = System.currentTimeMillis();
System.out.println(time); //输出的结果为: 1383835712828
通过上面的代码可以看出,输出的结果已经超出int类型的最大值,因此,JDK设计的返回类型为long型,该方法常常被用于计时操作。
【char类型】
字符类型char事实上是一个16位无符号整数(都是正数),这个值是对应字符的编码,Java字符类型采用Unicode字符集编码(通用码、统一码、万国码)
,而Unicode是世界通用的定长字符集,所有的字符都是16位来表示。例如:字符a实际的值为97,字符A实际的值为65,字符0实际的值为48。
字符直接量可以采用诸如:‘中’的形式,也可以采用16进制的表示形式,例如: ‘\u4e2d’,代码如下所示:
char c1 = ‘中’; //c1中存的是”中”的编码
char c2 = ‘\u4e2d‘; //‘4e2d’为‘中’所对应的16位Unicode编码的16进制表示形式
System.out.println(c1);
System.out.println(c2);
如上代码的输出结果:c1的值为中,c2值也为中,但c1和c2内部存储的其实是”中”这个字符所对应的Unicode码,即:一个无符号的整数。
对char型变量赋值
char abc=‘1‘;
System.out.println(abc); //输出1
System.out.println(abc+1); //输出50
char abc=1;
System.out.println(abc); //输出
System.out.println(abc+1); //输出2
在对char型变量赋值时,可以采用如下三种方式:
方式一:
字符直接量:形如‘A’,变量中实际存储的是该字符的Unicode编码(无符号整数值),一个char型变量只能存储一个字符。示例如下:
char c1 = ‘A‘;
方式二:
整型直接量:范围在0~65535之间的整数,变量中实际存储的即该整数值,但表示的是该整数值所对应的Unicode字符。示例如下:
char c2 = 65;
Unicode形式:形如‘\u0041’,Unicode字符的16进制形式。示例如下:
char c3 = ‘\u0041‘;
使用转义字符
char c = ‘\\‘;
System.out.println(c); //输出的结果为:\
‘\n‘ 表示回车符
‘\r‘ 表示换行符
‘\\‘ 表示反斜杠(\)
‘\‘‘ 表示单引号(‘)
‘\"‘ 表示双引号(")
‘ ‘ 表示空格符
“\t” 输出时,空格 //System.out.println(c+“\t”);
System.out.println("请选择功能:\n 1.查看余额 2.取款 3.缴电话费");
【boolean】
boolean类型适用于关系、逻辑运算, 表示某个条件是否成立, 只允许取值true或false,true表示条件成立, 而false表示条件不成立。
boolean型变量经常用于存储关系运算的结果,所谓关系运算就是比较两个变量的大小相等等关系(此知识点,后续详细介绍)。boolean示例代码如下所示:
int age = 18;
boolean isChild = age<16;
System.out.println(isChild); // isChild的值为false
boolean running = true;
boolean closed = false;
【变量命名】 值 //引用命名 对象 八种基本数据类型以值的形式存在于内存中,而不是对象
在java语言中,对于变量、常量、方法、类、包等等都有名字,将这些名字统一称之为java标识符,标识符的命名规则如下列表所示:
可以由字母、数字、“_”或“$”符组成,但是不能以数字开头。
中文可以作为变量名,但不提倡使用。
Java大小写敏感,即:严格区分大小写,在给命名变量时需要注意。
不能使用Java保留字(一些Java语言规定好的,有特殊含义的字符),如:int、if、else、for、break等。
【赋值】
public static void main(String[] args) {
int a, b = 10;
int c = a + b; // 编译错误 变量a并未赋初始值就直接使用了,违反了java语法的规定,变量使用之前必须初始化
System.out.prinltn(c);
}
public static void main(String[] args) {
int sum = 0; //声明同时初始化
int a = 5;
int b = 6;
sum = a + b;
System.out.println(sum);
}
public static void main(String[] args) {
int sum;
sum = 0; // 在使用sum变量之前对其进行初始化。
sum = sum + 100;
System.out.println(sum);
}
int b,c,d; //声明3个变量
【溢出】
两个整数进行运算时, 其结果可能会超过整数的范围而发生溢出,正数过大而产生的溢出,结果为负数;负数过大而产生的溢出,结果为正数。示例代码如下所示:
int a = 2147483647; //int类型整数的上限
int b = -2147483648; //int类型整数的下限
a = a + 1;
b = b - 1;
System.out.println("a=" + a); //输出结果: a=-2147483648 溢出,结果错误。
System.out.println("b=" + b); //输出结果: b=2147483647溢出,结果错误。
如果可能溢出时,把相乘的几个数中的第一个加上L/l,如果加在最后面,可能数在前面就已经溢出了,再加就没意义了。
初始化时超多21亿多则是编译错误,运算时超过21亿多则是溢出。
【数据类型】八种基本数据类型
boolean byte char short int long float double
String 字符串
int[] 非基本的数据类型(引用类型)
byte b1 =20>>>1;
byte b1 = 10;byte b=b1++;
byte b1 = 10, b2 = 20;byte b=(byte)(b1+b2);
【类型转换】
byte->short->int->long->float->double
char->int->long->float->double
强制转化:从大类型到小类型需要强制转换符,语法如下:
因为大类型的精度值大于小类型,取值范围大于小类型,所以,当使用强制转化时,有可能会造成精度的损失或者溢出,
所以,在使用强制转化时要求显式的告诉编译器,正在进行强制转换。
int a = 100;
int b = 200;
long c = a + b; //自动将int转化为long
long l1 = 1024l;
int i = (int) l1; //需要加强制转化符由于1024在int的范围内,所以没有产生溢出
long l = 1024L * 1024 * 1024 * 4;
int j = (int) l; //会产生溢出
System.out.println(j); // 结果为:0
double pi = 3.1415926535897932384;
float f = (float) pi; //会造成精度的损失,因为单精度的精确度小于double
System.out.println(f); //结果为:3.1415927
如果在一个表达式中出现了多种数据类型,则运算结果会自动的向较大的类型进行转化,
//由于有long型的直接量参与,整个表达式的结果为long
long distance = 10000 * 365 * 24 * 60 * 60 * 299792458l;
//由于有double型的直接量599.0参与,整个表达式的结果为 double
double change = 800 - 599.0;
//结果为0.0,右边都是int型数据运算结果也为int类型,结果为0,再赋值给double
型,将0转化为 0.0
double persent1 = 80 / 100;
//结果为0.8,右边表达式有double型直接量参与, 运算结果为double型
double persent2 = 80.0 / 100;
int直接量可以直接赋值给byte、char和short,只要不超过其表示范围。示例如下:
byte b = 97;
short s = 97;
char c = 97;
byte、char、short三种类型参与运算时,先一律转换成int类型再进行运算。示例如下:
byte b = 97;
int num = b + b; //num的值为194
byte b1=5;
byte b2=6;
//byte b3=b1+b2; //编译错误
byte b3=(byte)(b1+b2);
int b3=b1+b2;
【MyEclipseGen】
先拖入MyEclipse 8.6软件的一个包内,然后给这个类加一个包名,然后运行,填一个用户名,回车就可以得到注册码
然后在工具栏的MyEclipse中的第五个Subscription Information栏进行注册。
【运算符】
【算术运算符】
+ - * / % ++ --
%:取模运算 意为取余 例子:5%2 取余为1 ;2%8 取余为2 ;8.567%2 取余为0.567
++/-- : 单独使用时a++,在前在后无差别;被使用时c=a++,在前在后有差别。
a++>5,是先用a和5来比,之后a再加一;++a>5,是先用a加一,之后再与5来比。
扩展赋值运算符,比较推荐,因为方便。
a += 10; //相当于a=a+10
a *= 2; //相当于a=a*2
字符串拼接运算符
+
若两边都是数字,则做加法运算
若有一边是字符串,则做字符串拼接 例如:(“age=”+age+“岁了”) //age=37
则输出 age=37岁了
String a=100+“”+300; //“100”+300 输出100300
String a=”“+100+300; //“100”+300 输出100300
Steing b=100+300+“”; //400+“” 输出400
System.out.println(2+2) // 输出4
System.out.println(‘2’+‘2’) // 输出100
System.out.println(2+”2“) // 输出22
【关系运算符】
Java中的关系运算符用于判断数据之间的大小关系,包括大于(>)、小于(<)、大于等于(>=)、小于等于(<=)、等于(= =)、不等于(!=) 六个运算符。
= =:是等于号; =:是赋值。
【逻辑运算符】
与(&&) 两个都要对 一个&指不会短路的与
或(||) 两个只要有一个对 一个|指不会短路的或
非(!) 一个反着来
逻辑运算的结果还是boolean型。
Java逻辑运算中的&&和||有短路的特性,当第一个关系表达式就可以判断出整个表达式的结果时,就不会再去判断后面的第二个表达式。
对于“&&”,当第一个操作数为false时,将不会判断第二个操作数,因为此时无论第二个操作数是什么最后的结果一定是false;
对于“||”,当第一个操作数为true时,将不会判断第二个操作数,因为此时无论第二个操作数为何,最后的运算结果一定是true。
示例代码如下所示:
int i = 100, j = 200;
boolean b1 = (i > j) && (i++ > 100);
System.out.println(b1); // 结果为:false
System.out.println(i); // 结果为:100,发生短路,i++不会被执行
boolean b2 = i > 0 || j++ > 200;
System.out.println(b2); // 结果为:true
System.out.println(j); // 结果为:200,发生短路,j++不会被执行
赋值运算符
字符运算符
三目运算符
一元运算符:! ++ --
二元运算符:+ - * /
三元运算符:
条件运算符又称“三目”运算符,其结构为:boolean表达式 ? 表达式1:表达式2。
条件运算符的规则如下: //?: ?:
先计算boolean表达式;
如果boolean表达式的值为true,整个表达式的值为表达式1的值;
如果boolean表达式的值为false,整个表达式的值为表达式2的值。
示例代码如下:
int a = 100, b = 200;
int flag = a > b ? 1 : -1; //因为a>b为false,所以整个表达式的值为-1,将其赋给flag,即:flag的值为-1。
【if】
(1)
int a=scan.nextInt();
if (a>10){
if(a>20){
System.out.println("A");
}else{
System.out.println("B");
}
}else{
System.out.println("C");
}
(2)
if(score>=90) {
System.out.println("A");
} else if (score>=80) {
System.out.println("B");
} else if(score>=60) {
System.out.println("C");
} else {
System.out.println("D");
}
【SWITCH】
int num = 2; //可以用 byte short char int
switch(num) {
case 1:
System.out.println(“呼叫教学部”);
break; //跳出switch
case 2:
System.out.println(“呼叫人事部”);
break;
default: //所有case都没有匹配时执行。
System.out.println(“人工服务”);
}
从JDK 7.0开始,switch-case可以支持字符串表达式,将更加方便程序的操作。
【循环结构】
(while、do…while、for)
while( boolean表达式 ) {
}
while语句的执行过程为,首先计算boolean表达式的值,而后进行判断,若值为true则执行语句块,语句块执行完后再次判断boolean
表达式的值,如果为true则继续执行语句块,如此循环往复,直到boolean表达式的值为false时退出while循环而执行while之后的语句。
int x = 0;
while ( x < 10 ) {
if ( 5 == x )
{
break;
}
System.out.println(x);
x ++ ;
}
分析上面的代码得出结论,输出结果为0 1 2 3 4,因为当x等于5时执行break语句直接退出循环结构了,即if语句块后面的输出x的值以及x++不再被执行。
do-while
do-while语句的执行过程为,先执行语句块,再判断boolean表达式,如果为true则再次执行语句块,如此循环往复,直到boolean表达式的
值为false时止。也就是说,do-while语句,无论boolean表达式是否为true,都先执行一次语句块。
do {
语句块
} while( boolean表达式 ) ;
注意:while和do-while语句的不同仅仅体现在第一次就不满足条件的循环中;如果不是这样的情况,while与do-while可以互换。
示例1:while循环方式
int pwd = 0;
while ( 123 != pwd){
System.out.print(“密码:”);
pwd = scanner.nextInt();
}
示例2: do-while循环方式
int pwd ;
do{
System.out.print(“密码”);
pwd = scanner.nextInt();
} while ( 123 != pwd) ;
分析示例1与示例2得出结论,运行结果完全一样。这是因为两段代码第一次的while条件都满足,此时while与do-whlie可以互换,所以结果完全一样。
示例3:for循环变量
for ( 表达式1;表达式2;表达式3 ) {
语句块(循环体)
}
for(int count =0;count<10;count++){ //1 2 3
System.out.println("行动是成功的阶梯"); //4
}
例子1.1:
int j = 0;
for(int i = 0;i < 100;i++){
j = j++;
}
System.out.println(j); //输出j=0
例子1.2:
int j = 0;
for(int i = 0;i < 100;i++){
j++;
}
System.out.println(j); //输出100
例子:1.3
int j = 0;
int c = 0;
for(int i = 0;i < 100;i++){
c=j++;
}
System.out.println(c); //输出99
程序运行顺序是1 2 4 3 2 4 3 2 4 3 2
for语句,首先计算表达式1,接着执行表达式2,若表达式2的值等于true,则执行大括号中的语句块,接着计算表达式3,
然后再判断表达式2的值。依次重复下去,直到表达式2的值等于false。
1可以挪到上面,3可以挪到下面,但分号不可以省。2如果省了就变成无限循环。
for ( int i =1 , j = 6 ; i <= 6 ; i +=2 , j -=2 ) {
System.out.println(“ i , j = “ + i + “,” + j );
}
上面的代码的执行逻辑如下:
i , j = 1 , 6
i , j = 3 , 4
i , j = 5 , 2
【continue】
continue语句只能用于循环中,它的作用为跳过循环体中剩余语句而执行下一次循环,
int sum = 0;
for(int i=1; i<=100; i++){
if( i % 10 == 3 ){
continue;
}
sum += i;
}
System.out.println(sum);
上面的程序需要统计1到100的累加和,条件是跳过所有个位为3的,此案例通过在if语句中使用continue
实现了跳过for语句中剩余的循环体语句,本程序最终sum的值为: 4570。
int sum = 0;
for(int i=1; i<=100; i++){
if( i % 10 != 3 ){
sum += i;
}
}
System.out.println(sum);
【循环问题】
如果业务可以转换为“当……“这样的句式时,优先选择while语句来实现。
如果业务可转换为”直到……”这样的句式时,优先选择do-while语句来实现。
如果业务中可以获取到一个确切的循环次数时可以考虑使用for循环来实现,
循环嵌套 外面循环走一次,内面循环走所有次。
【数组】数组是一种非基本的数据类型(引用类型)
数组为相同数据类型的元素组成的集合,数组元素按线性顺序排列,所谓线性顺序是指除第一个元素外,每一个元素都有唯一的
前驱元素;除最后一个元素外,每一个元素都有唯一的后继元素(“一个跟一个”),可以通过元素所在位置的顺序号(下标)
做标识访问每一个元素(下标从0开始,最大到元素个数-1)
int[] arr=new int[4]; //一个整型数组 //声明int型数组arr,包含4个元素。且每个元素都是int型,每个元素默认为0
double[] arr=new int[4]; //声明double型数组arr,包含4个元素。且每个元素都是double型,每个元素默认为 0.0
boolean[] arr=new int[4]; //声明boolean型数组arr,包含4个元素。且每个元素都是boolean型,每个元素默认为false
byte short char int long 为0
float double为0.0
boolean 为false
注意char的默认值是0(码)而不是‘0’(字符)所代表的48.
int[] arr={1,3,5,7}; //4个元素,分别是1,3,5,7
int[] arr=new int[]{1,3,5,7}; //4个元素,分别是1,3,5,7
int[] arr;
arr={1,3,5,7}; //编译错误,{}赋值只能声明的同时初始化
arr=new int[]{1,3,5,7}; //正确
int[] arr=new int[4];
System.out.println(arr.length); //数组的长度是4 arr.length指数组的长度
int[] arr=new int[]{1,3,5,7};
System.out.println(arr[arr.length-1]); //输出arr中的最后一个元素
例子:
int[] arr = new int[10];
for ( int i = 0 ; i < arr.length ; i ++ ){
arr [ i ] = 100;
}
正序输出:
int[ ] arr = new int [ ] {10,20,30,40,50 } ; //正序输出
for ( int i=0; i< arr.length; i++) {
System.out.println ( arr[ i ] ) ;
}
逆序输出:
int[] arr5 = new int[] {10,20,30,40,50 } ; //逆序输出
for ( int i = (arr5.length -1) ; i >= 0 ; i -- ) {
System.out.println ( arr5[ i ] ) ;
}
【数组的复制】
一:System.arraycopy
public static void arraycopy(Object src, int srcPos,Object dest, int destPos, int length)
如上代码的,每一个参数的意义见下列表:
src:源数组
srcPos:源数组中的起始位置
dest:目标数组
destPos : 目标数组中的起始位置
length:要复制的数组元素的数量
通过下面的代码,可实现数组的复制:
int[ ] a = { 10 ,20 ,30 ,40 ,50 };
int[ ] a1 = new int[ 6 ] ;
System.arraycopy( a , 1 , a1 , 0 , 4 ); //结果:20,30,40,50
如上方法的意义可以理解为:将a数组的从下标1(第二个)开始的4个元素复制到a1数组中,a1数组从下标0位置开始赋值。
程序执行完后,a1的值为20,30,40,50,0,0。其交互效果如图 – 3所示:
二:Arrays.copyOf()方法示例代码如下所示:
int [ ] a = { 10,20,30,40,50 } ;
int [ ] a1 = Arrays . copyOf ( a, 6 );
上段代码执行后,a1的结果为:10 20 30 40 50 0,分析其执行过程为:声明一个整型数组,数组变量名称为a,赋初始值为10 20 30 40 50,
声明整型数组a1,将a数组数据复制到a1数组,设置其为6个长度,因a数组只有5个元素,所以最后一位补0。故而输出结果为10 20 30 40 50 0。
总结出Arrays.copyOf()方法的特点如下列表所示:
生成的新数组是原始数组的副本;
newLength小于源数组,则进行截取;(自己通过代码演示效果);
newLength大于源数组,则用0或 null进行填充;
System.out.println("新数组中的数据"+Arrays.toString(arr)); //显示整个数组
//新数组中的数据[71, 45, 66, 90, 58, 91, 5, 44, 43, 50, 91]
【排序算法】
常用排序算法有:插入排序、冒泡排序、快速排序等。
long a=System.currentTimeMills();
冒泡算法 //3000毫秒
long b=System.currentTimeMills();
System.out.println(b-a); //得3000毫秒
Arrays.sort(arr)比冒泡排序要块 //升序排列 arr是函数的名称
System.out.println("新数组中的数据"+Arrays.toString(arr));
int[] a=new int[]{1,0,1,0,1,5,5,8};
int[] b=new int[]{5,5,98,4,2,3,5,4,5,4,2,5,4};
System.arraycopy(a,0,b,0,5); //a,0,b,0,5(长度不可以长于上面的也不可以长于下面的)
System.out.println(Arrays.toString(b));
【方法】(函数,过程)
方法常常用于封装一段特定的逻辑功能,例如:执行计算或操作
方法可以在程序中反复被调用,这样,就可以减少代码的重复,更便于程序的维护。
oid say() { } //无参方法
void say( string name ) { } //1个参数方法
int sum ( int num1 , int num2 ) { } //2个参数方法
【返回值】
若方法不需要返回数据,将返回值类型声明为void。
若方法需要返回数据,将返回值类型声明为特定数据类型。
方法的返回值 取钱 要返回值(返回钱) 存钱 可以没有返回值,没有凭条(因为网上数据已经改了)
int num
【参数】
double b=Math.sqrt(9);
有参数
double b=Math.random();
没参数
public static int sum(int num1 , int num2 ){ }
修饰词 返回值 方法名 参数 方法体
public static void s(){} //无参,void表示无返回值
sayHello2(); //System.out.println();不需要这个
//无参无返回值
public static void sayHello2(){
System.out.println("大家好,我叫张三");
}
double num=sayHello3(); //
System.out.println(num); //250.25
//无参有返回值
public static double sayHello3(){
return 250.25; //return;编译错误,必须返回一个值 return “wkj”;编译错误,返回值类型不匹配
}
sayHello("zhangsan"); //sayHello();编译错误,没提供参数 //sayHello(25);编译错误,参数类型不匹配 //System.out.println();不需要这个
//有参无返回值
public static void sayHello(String name){
System.out.println("大家好,我叫"+name);
return; //仅仅表示方法结束
}
int b=sayHello4(2,5);
System.out.println(b);
//有参有返回值
public static int sayHello4(int num1,int num2){
int num =num1+num2;
return num;
}
salary:薪水 demo:演示 var:定义变量 score:成绩 DataTypeDemo:数据类型演示 UnitPrice:单价 qty:数量
cost:花费 count:计数 correct:正确的 Error:错误 Date:日期 index:下标 array:数组 letter:字母
flag:插旗 cell:格子 info:信息 row:行 col:列 drop:向下 Override:重写 Overload:重载
area:面积 square:正方形 shape:图形 circle:圆形 circumference:周长 remove:移动 set:设定
add:增加 subtract:减去 Bill:账单 drawMoney:取款 getBalance:查询余额 award:奖品 checkPwd:检查密码
IDcard:身份证postalCode:邮编value:价值 compare:比较 matches:比较 util:有用的 regex:正则表达式
identitycard//Pattern:模式 Syntax:语法 Format:格式 Bounds:出界 Cast:造型
${cursor} 光标(用来设置快捷键)
Android
RelativeLayout 相对布局
LinearLayout 线性布局
TableLayout 表格布局
FrameLayout 帧布局
GridLayout 网格布局
TableRow 表格行
TextView 显示文本的组件
Adapter 适配器
stretchColumns 伸展 设置网格的列数
android:stretchColumns="0,1,2"> <!--拉伸使平均分布 -->
android:stretchColumns="1" android:shrinkColumns="1"这两个属性是TableLayout所特有的,也是这两个属性影响了子对象的布局。 表格布局是按照行列来组...
classCastException:类型转换异常
class Var{
int a; //实例变量 //属于成员变量
static int b; //类变量,静态变量 //属于成员变量
public void display(String str1){ //参数变量
String str2; //局部变量
}
}
取反 ~3 等于-4
第二本书:面向对象
【面向过程】
面向过程的结构化程序设计
/** 打印员工信息的方法 */
public static void printEmpInfo(String name,int age, //面向过程
char gender,double salary) {
System.out.println("--------------------");
System.out.println("姓名: " + name);
System.out.println("年龄:" + age);
System.out.println("性别:" + gender);
System.out.println("薪水:" + salary);
}
/** 打印雇员信息 */
public static void main (String[ ] args ){
//雇员1
String emp1Name = "黄河大虾";
int emp1Age = 25;
char emp1Gender = ‘男‘;
double emp1Salary = 8000.00;
//打印员工信息
printEmpInfo(emp1Name, emp1Age, emp1Gender, emp1Salary);
//修改员工工资(增长20%)并打印
emp1Salary *= 120.0 / 100.0;
printEmpInfo(emp1Name, emp1Age,emp1Gender, emp1Salary);
}
【抽象数据类型】(自己创造数据类型)
面向对象的第一步就是抽象数据类型,所谓抽象数据类型可以理解为:
将不同类型的数据的集合组成个整体用来描述一种新的事物。像如上程序中,可以将姓名String、年龄int、性别char、工资double这4个不同类型的数据组成一个整体来描述雇员这个新事物。
【面向对象】
【类】 //雇员类,一种数据类型(非基本的)
类定义了一种抽象数据类型,而类不但定义了抽象数据类型的组成(成员变量),同时还定义了对该类型可以实施的操作(方法)。看如下代码定义了雇员类:
1.类,一种数据类型
2.现实生活中是由很多很多对象组成的
基于这些对象,抽出了类(动物是类,姚明是对象)
3.对象是一个真实的个体。类为类别。
4.类可以包含:
a.所有对象所共有的特征/属性-------数据(变量)
b.所有对象所共有的行为---------对数据的操作(方法)
5.一个类可以创建多个对象
同一个类创建的对象,结构相同,数据不同。
6.引用类型间画等号:指向同一个对象; Cell c1=new Cell(); Cell c2=c1; //有new
对一个数据的修改,会影响另一个
基本类型间画等号:赋值 int a=5; int b=a;
对一个数据的修改,不会影响另一个
7.null:空,不再指向任何对象。不能做任何操作。
/**进一步修改后的雇员类*/
public class Emp{ //面向对象
String name;
int age;
char gender;
double salary;
/**打印信息的方法*/
public void printInfo() { //定义在类中,可直接对成员变量进行操作
System.out.println("--------------------");
System.out.println("姓名: " + name);
System.out.println("年龄:" + age);
System.out.println("性别:" + gender);
System.out.println("薪水:" + salary);
}
}
/**针对修改后的Emp类的使用方式*/
public class EmpManager {
public static void main(String[] args) {
Emp emp2 = new Emp(); // cell c = new cell();
// 类(变量) 引用 对象 //类引用对象 变量引用对象
emp2.name = "白发馍女";
emp2.age = 24; //对象.
emp2.gender = ‘女‘;
emp2.salary = 6000;
/**调用方法打印信息*/ //创建完Emp对象后,对其成员变量赋值,然后调
emp2.printInfo(); //用其printInfo()方法打印各个成员变量信息
emp2.salary *= 125.0 / 100.0;
emp2.printInfo();
}
}
java中一个对象引用先后指向两个对象时,前一个对象是否是被释放掉?
第一个new的数组对象失去引用,会被垃圾回收器回收
java内存管理机制比较特殊,并不是对象不被引用了就会马上回收,也就是仍然在内存中,
直到垃圾回收器执行回收操作,不过这些java底层有一套机制,我们暂时不用纠结他什么时候释放内存
只要引用释放掉就可以了
通过上面的代码,很好的实现了对数据的封装,并且实现了数据与方法的统一。这种方式即为面向对象方式,即:以对象为中心来构建软件系统。
成员变量的默认值 //赋初值
定义好类之后,可以创建该类的对象,对象创建之后,其成员变量可以按照默认的方式初始化;对象成员变量的默认初始化值规则如下图 - 5所示:
byte short int long float double 默认值 0
boolean 默认值 false
char 默认值 \u0000 无
引用类型 默认值 null //String 雇员类 引用数组 默认值 null //基本类型数组的初始默认值为具体值
对象是一个客观存在的实体,是面向对象编程过程中分析与解决问题的出发点与基础。对象的实质就是内存中的一块数据存储区域,其数据结构由定义它的类来决定。
类是用于构建对象的模板,对象通过类的实例化产生,一个类可以创建多个对象,每个对象拥有自己的数据和行为。
class 类名 {
成员变量类型 变量名称;
………
返回值类型 方法名称(参数列表) {
方法体………
}
}
cell c = new cell(); //类引用对象
类 引用 对象
【方法的签名】
方法的签名包含如下两个方面:方法名和参数列表。
Java语法规定,一个类中不可以有两个方法签名完全相同的方法,即:一个类中不可以有两个方法的方法名和参数列表都完全相同,但是,如果一个类的两个方法只是方法名相同而参数列表不同,是可以的。
【方法的重载】
方法名相同,参数列表不同
class Aoo{
void say(){}
void say(String name){}
void say(String name ,int age ){}
void say(int age,String name){}
//void say(){return 1;} 编译错误和void say(){}重了
// void say(String address){} 编译错误和void say(String name){}重了
}
【构造方法】
通过构造方法初始化成员变量 //没有返回值
class Cell {
int row ; //成员变量 (堆中)在方法外
int col ; //成员变量
public Cell (int row1 , int col1){ //构造方法不需要返回值 //局部变量(栈中) 在方法内
row = row1; //默认指this.row = row1; 指c1.row=row1; c1.row=15;
col = col1;
}
}
class TestCell {
public static void main(String args[ ] ){
Cell c1 = new Cell( 15 , 6 );
printCell(c1);
}
}
1.常常用于给成员变量赋初值
2.语法与类同名,没有返回值
3.在创建对象new自动调用
4.若自己不写构造方法,则系统会提供一个默认的无参构造;若自己写了,就不在提供空的 Cell c1 = new Cell(); // Cell(){}
5.构造方法可以重载
【this】
1)this.成员变量--------访问成员变量
2)this.方法名()----调用方法
3)this()------调用构造方法
this用来指代当前对象,哪个对象调用,就指那个对象
在方法中访问成员变量的前面,默认有一个this //T(int row,int col){ this.cells[0]=new Cell(row,col);}
this在成员变量和局部变量相同时,不能省略
【扩展:(this)】
1.this 是什么?
this 是一个引用,它的值指向对象,是一个对象的地址。
2.this 用在哪里?
this 应用在非静态方法内部,永远指向调用这个方法的对象。
FAQ? 一个类可以有很多个类的对象
那this具体指向哪个对象呢?
取决于哪个对象调用此方法。
3.this的使用形式?
1)this.属性/方法
2)this(参数列表): 应用在构造方法内部,
用于调用本类其它构造方法,并且只能写在第一行。
注意:在内部类中访问外部类的this时使用"外部类的名字.this";
row++ //默认为this.row++ //指c.row++ this就是指c
1)
class Cell {
int row ; //成员变量 (堆中)在方法外
int col ; //成员变量
public Cell (int row , int col){ //构造方法不需要返回值 //局部变量(栈中) 在方法内
this.row = row; //指c1.row=row; c1.row=15;
this.col = col;
}
}
class TestCell {
public static void main(String args[ ] ){
Cell c1 = new Cell( 15 , 6 );
printCell(c1);
}
}
2)Cell(){
this(0,0); //(0,0)可以写但没意义,不能是(0,0,0)
}
等于
Cell(int n){
this(n,n);
}
等于
Cell (int row , int col){
this.row = row;
this.col = col;
例子:
package day28;
class Good {
int a;
int b;
public Good() {
this(00); //没有这步就是输出0 0
}
public Good(int a){
this(15,16);
}
public Good(int a, int b) {
super();
this.a = a;
this.b = b;
}
}
class Test0{
public static void main(String[] args) {
Good t= new Good();
System.out.println(t.a+" "+t.b); //15 16
}
}
引用类型数组的声明
Cell [ ] cells = new Cell [ 4 ] ;
new Cell[4]实际是分配了4个空间用于存放4个Cell类型的引用,并赋初始值为null,而并非是分配了4个Cell类型的对象。
package oo.day02;
public class Array {
public static void main(String[] args) {
int[][] arr=new int[3][4];
for(int i=0;i<arr.length;i++){
for(int j=0;j<arr[i].length;j++){
arr[i][j]=100;
System.out.print(arr[i][j]+" ");
}
}
}
}
【super】
super();调用父类的无参数构造方法。可省略不写。 // super(5);调用父类的有参数构造方法
super.方法()----调用父类的方法
super.成员变量----调用父类的成员变量
【方法区】【内存】【JVM】
在JAVA中,有java程序、虚拟机、操作系统三个层次,其中java程序与虚拟机交互,而虚拟机与操作系统交互。编译好的java字节码文件运行在JVM中。
程序中无论代码还是数据,都需要存储在内存中,而java程序所需内存均由JVM进行管理分配,
开发者只需关心JVM是如何管理内存的,而无需关注某种操作系统是如何管理内存的,这就保证了java程序的平台无关性。
JVM会将申请的内存从逻辑上划分为三个区域:堆、栈、方法区。这三个区域分别用于存储不同的数据。
堆内存用于存储使用new关键字所创建的对象;
栈内存用于存储程序运行时在方法中声明的所有的局部变量;
方法区用于存放类的信息,Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区。
类的各种信息(包括方法)都在方法区存储。
Foo foo = new Foo();
foo.f();
以上代码的内存实现原理为:
1.Foo类首先被装载到JVM的方法区,其中包括类的信息,包括方法和构造等。
2.在栈内存中分配引用变量foo。
3.在堆内存中按照Foo类型信息分配实例变量内存空间;然后,将栈中引用foo指向foo对象堆内存的首地址。
4.使用引用foo调用方法,根据foo引用的类型Foo调用f方法。
【堆内存】
【生命周期】
成员变量的生命周期
当声明好对象之后,对该对象(堆中的Cell)的访问需要依靠引用变量(栈中的c),那么当一个对象没有任何引用时,
该对象被视为废弃的对象,属于被回收的范围,同时该对象中的所有成员变量也随之被回收。
可以这样认为,成员变量的生命周期为:从对象在堆中创建开始到对象从堆中被回收结束。
【null】
请看如下的代码,演示了对象不再被引用:
Cell c = new Cell();
c = null ;
当将c赋值为null时,表示c不再指向刚刚分配的对象空间,此时成员变量失效。 //没有地址,再不能指向任何东西
Cell c = new Cell();
Cell c1=c; //此时不会被回收,虽然栈中c不再指向堆中Cell,但栈中c1依然指向堆中Cell
c = null ;
【垃圾回收机制】 //堆
垃圾回收器(Garbage Collection,GC)是JVM自带的一个线程(自动运行着的程序),用于回收没有任何引用所指向的对象。
GC线程会从栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的,若GC无法跟踪到某一块堆内存,
那么GC就认为这块内存不再使用了,即为可回收的。但是,java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。
【内存泄露】
Java程序的内存泄露问题
内存泄露是指,不再被使用的内存没有被及时的回收,严重的内存泄露会因过多的内存占用而导致程序的崩溃。在程序中应该尽量避免不必要的内存浪费。
GC线程判断对象是否可以被回收的依据是该对象是否有引用来指向,因此,当确定该对象不再使用时,应该及时的将其引用设置为null,这样,该对象即不再被引用,属于可回收的范围。
【非堆】----【栈】
栈用于存放方法中的局部变量
【生命周期】
局部变量的生命周期
一个运行的Java程序从开始到结束会有多次方法的调用。JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。
一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。当某一个方法调用完成后,其对应的栈帧将被清除,局部变量即失效。
main(){
Aoo o=new Aoo();
o.test(55); // 栈帧 正在调用中的方法 存储了该方法的参数、局部变量等数据。
}
成员变量和局部变量
成员变量与局部变量的差别如下:
局部变量:
1) 定义在方法中;
2) 没有默认值,必须自行设定初始值;
3) 方法被调用时,存在栈中,方法调用结束时局部变量从栈中清除;
成员变量:
1) 定义在类中,方法外;
2) 由系统设定默认初始值,可以不显式初始化;
3) 所在类被实例化后,存在堆中,对象被回收时,成员变量失效;
堆内存 非堆----栈 非堆----方法区
【方法区】
方法区用于存放类的信息,Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区。类的各种信息(包括方法)都在方法区存储
方法只有一份
当类的信息被加载到方法区时,除了类的类型信息以外,同时类内的方法定义也被加载到方法区;
类在实例化对象时,多个对象会拥有各自在堆中的空间,但所有实例对象是共用在方法区中的一份方法定义的。意味着,方法只有一份。看如下代码:
JFrame f1 = new JFrame();
JFrame f2 = new JFrame();
f1.setSize(200, 300);
f2.setSize(300,400);
如上的代码中,对象有两个,但是setSize方法只有一份,分别针对f1指向的对象和f2指向的对象调用了两次。
【继承】
泛化的过程
前面的案例中定义了T类和J类, 通过分析可以发现, 在这两个类中存在着大量的重复代码,像cells属性、print方法、drop方法、
moveLeft方法、moveRight方法,在这两个类中都存在,并且实现上基本也是相同的,本着代码重用的原则,可以使用继承的方式来实现。
首先,构建T类和J类的父类Tetromino类,将公共的(T类和J类公有的)信息存放在父类中, T类和J类继承Tetromino父类。此时,子类即可以共享父类的数据。这个过程就是泛化的过程。
【extends】关键字
使用继承可以实现代码的重用,在java语言中,需要通过extends关键字实现类的继承。继承完成后,
子类(Sub class)可以继承父类(Super class)的成员变量及成员方法,同时子类也可以定义自己的成员变量和成员方法。届时,子类将具有父类的成员及本类的成员。
需要注意的是,Java语言不支持多重继承,即:一个类只能继承一个父类,但一个父类可以有多个子类。看下面的代码:
【继承】:
目的:避免代码重复;
通过:extends;
父类:所有子类所共有的
子类:子类所独有的
一个子类只能继承一个父类;
继承具有传递性a继承->b; b继承->c;
【System.gc()方法】
GC的回收对程序员来说是透明的,并不一定一发现有无引用的对象就立即回收。一般情况下,当我们需要GC线程即刻回收无用对象时,
可以调用System.gc()方法。此方法用于建议JVM马上调度GC线程回收资源,但具体的实现策略取决于不同的JVM系统。
分析上面的代码,在子类构造方法中没有写super调用父类构造方法,这时编译器会默认添加super()来调用父类的无参构造方法,但是父类中又没有定义无参的构造方法,因此会发生编译错误。
针对上面的问题,可以有两种解决方案,方案一为在父类中添加无参的构造方法,
方案二为在子类构造方法中显示调用父类的有参构造方法(常常使用),这样可以保证父类的成员变量均被初始化,参见下面的代码:
class Goo extends Foo {
int num;
Goo(int value, int num) {
super(value);
this.num = num
}
}
【向上造型】
//动物是动物
Animal 01=new Animal();
//老虎是老虎
Tiger 02= new Tiger();
//一个新的老虎是动物
Animal 03= new tiger();
//动物是老虎 //编译错误,逻辑错误
Tiger 04=new Animal();
【向上造型】
(1)
Same t =new SameT(5, 5); //向上造型
printwall(t); //向上造型后传值
public static void printwall(Same same) { }
(2)
SameJ j= new SameJ(3,4);
printwall(j); //传值的同时向上造型
public static void printwall(Same same) { }
(A)
class Moo{
int m;
void show(){}
}
class Zoo extends Moo{ //隐藏一个Zoo(){super();} 隐藏一个无参构造,默认super();调用父类的无参数构造方法
int n;
void say(){}
}
Moo a=new Zoo(); //一个子类到父类
a.m=1;
a.show();
// a.n=2; //编译错误,只能点出父类的,能点出什么看类型,左边的。
///////
Zoo b=new Zoo(); //子类是子类 全可以点出来
b.m=1;
b.show();
b.n=2;
b.say();
Moo c=new Moo(); //父类是父类
c.m=1;
c.show();
//c.n=2; //编译错误,
//c.say(); //编译错误,
(B)
int row; // 行号
int col; // 列号
Cell(int row,int col){ //有参构造方法
this.row=row;
this.col=col;
}
Cell(int n){ //有参构造方法
this(n, n+1);
}
Cell(){ //无参构造方法
this(0,0);
}
【父类】
父类的构造方法不是被继承的,而是被调用的。
【重写】
在java语言中,子类可以重写(覆盖)继承自父类的方法,即方法名和参数列表与父类的方法相同,但是方法的实现不同。
Person p1 =new Person();
p1.sayHi(); //调用父类Person的。
Student s1=new Student();
s1.sayHi(); //调用子类Student的。
当子类重写了父类的方法后,该重写方法被调用时(无论是通过子类的引用调用还是通过父类的引用调用),运行的都是子类重写后的版本。看如下的示例:
class Foo {
public void f() {
System.out.println("Foo.f()");
}
}
class Goo extends Foo {
public void f() {
System.out.println("Goo.f()");
}
}
class Test{
public static void main(String[] args){
Goo obj1 = new Goo();
obj1.f();
Foo obj2 = new Goo();
obj2.f();
}
}
分析代码得出结论:输出结果均为“Goo.f()”,因为都是Goo的对象,所以无论是子类的引用还是父类的引用,最终运行的都是子类重写后的版本。
1.两同:方法名,参数列表相同
2.1)子类返回值类型小于或等于父类的:
1.1)父类void ------子类也必须是void
1.2)父类八种基本类型 ---子类也必须是八种基本类型
1.3)父类引用类型-------子类返回值类型小于或等于父类的
2)子类方法抛出的异常小于或等于父类
3.子类的访问权限大于或等于父类
【重载重写】
重载Overload: 是指在一个类中定义多个方法名相同但参数列表不同的方法,在编译时,根据参数的个数和类型来决定绑定哪个方法。看类型(编译器)
重写Override: 是指在子类中定义和父类完全相同的方法(方法名,参数列表都相同),在程序运行时,根据对象的类型(而不是引用类型)而调用不同的方法。看对象(运行器)
向上造型能点出什么看类型 强制类型转换 看对象
【包的概念】package语句
定义类时需要指定类的名称,但是如果仅仅将类名作为类的唯一标识,则不可避免的出现命名冲突问题,
这会给组件复用以及团队间的合作造成很大的麻烦!因为原则上来说,类名是不可以重复的。
在Java语言中,命名冲突问题是用包(package)的概念来解决的,也就是说,在定义一个类时,除了定义类的名称一般还要指定一个包的名称,定义包名的语法如下所示:
package 包名;
需要注意的是,在定义包时,package语句必须写在Java源文件的最开始处,即在类定义之前,如下面的语句将为Point类指定包名为“test”:
package test;
class Point{
……
}
一旦使用package指定了包名,则类的全称应该是“包名.类名”,如上语句的Point类的全称为test.Point。
使用package即可以解决命名冲突问题,只要保证在同一个包中的类名不重复即可,而不同的包中可以定义相同的类名,
例如:test1.Point和test2.Point是两个截然不同的名称,虽然类名相同,但包名不同,亦表示两个完全不同的类。
在命名包名时,包名可以有层次结构,在一个包中可以包含另外一个包,可以按照如下的方法定义package语句:
package 包名1.包名2…包名n;
org.apache.commons.lang.StringUtil
如上类的定义可以分为4个部分,其中,StringUtil是类名,org.apache.commons.lang是多层包名,其含义如下:org.apache
表示公司或组织的信息(是这个公司或组织域名的反写);commons表示项目的名称信息;lang表示模块的名称信息。
同一个包内的类,可以直接引用
不同包内,不可以直接引用
要用 import 包名+类名 //引用两个同类名的类时 import p1.Aoo; import p2.Aoo; //p1.Aoo a=new p1.Aoo() ; p2.Aoo a=new p2.Aoo() ;
完全限定名 包名+类名 ---不建议p1.Aoo a=new p1.Aoo() ;
【封装】
封装的意义就是提供可调的稳定的功能
降低代码出错的可能性,更便于维护。
当内部实现细节改变时,只要保证对外的功能定义不变,其他的模块不需要更改。
在软件系统中,封装常常需要依靠一些访问控制修饰符来实现。
【访问修饰符】
public:公共的,任何地方都可以
protected:受保护的,本类,子类,同包类
默认的:什么也不写, 本类,同包类
private:私有的,本类
类只能用public或默认的来修饰
类中的成员或方法都可以
【static】 静态的
1. static修饰成员变量 静态变量
1.1)属于类的,而不属于对象
1.2)和类的信息一起存储在方法区,只有一份。
1.3)常常通过;类名来访问
1.4)何时用:所有对象都一样时
// Students.classname="JSD1503";
class Same { // 类的共同点,被继承的父类
Cell[] cells;
static int size; //
Same() {
this.cells = new Cell[4];
Same.size=100; //
System.out.println(Same.size);
}
}
2. static修饰方法 静态方法
2.1)没有this传递
2.2)静态方法中不能直接访问实例成员
可以直接访问静态成员 //但非static静态方法可以访问static成员(方法)
2.3)常常通过类名来访问
2.4)何时用:方法的操作与对象无关与成员变量无关,而仅与参数相关 //很少用 //Math.random();
3. static块 静态块
3.1)static块为属于类的代码块,在类加载期间执行的代码块,只执行一次,因为类只加载一次
3.2)可以用来在软件中加载静态资源(图像、音频等等)。
成员变量可分为
实例变量 不用static修饰
静态变量 static修饰
静态变量输出时,可以通过类名来访问
Ioo o1=new Ioo();
System.out.println(Ioo.b) ; //类.
System.out.println(o1.b) ; //可以但不建议
//方法中访问成员变量前面默认有个this
实例成员必须通过对象.来访问
静态方法没有隐式this
【final】
1)修饰变量:变量不可以被修改
1.1)成员变量: 声明同时初始化 构造方法中初始化 //之后就不可以在其他方法中改变其值的大小,不然就是编译错误
A)
class Loo{
final int a=100; //声明同时初始化
final int b;
Loo(){
b=200; //构造方法中初始化
}
void show(){
final int c; //用之前初始化即可 局部变量
//a=250; //编译错误,不可被修改
}
}
B)
public class Emp {
private final int no = 100; // final成员变量声明时初始化
public static void main(String[] args) {
no = 99;
}
}
如上的语句,no=99会出现编译期错误,因为final的变量不可被改变。
1.2)局部变量:在使用之前初始化即可
2)修饰方法:方法不可以被重写 //可以重载,不可以被重写
class Moo{
void show(){}
final void say(){}
void say(int a){}
}
class Noo extends Moo{
void show(){}
// void say(){} //无法被重写
}
3)修饰类:类不可以被继承
final class Moo{ //可以继承别人
void show(){}
final void say(){}
}
/*
class Noo extends Moo{ //Moo不能被继承
void show(){}
}
*/
【static final常量】
static final 修饰的成员变量称为常量,必须声明同时初始化,并且不可被改变。常量建议所有字母大写。
实际应用中应用率较广,因为static final常量是在编译期被替换的,可以节约不必要的开支,如下代码演示了static final的用法:
class Foo {
public static final int NUM = 100; //public final static int NUM = 100; static 和 final二者的前后顺序不限。
}
class Goo {
public static void main(String[] args) {
System.out.println(Foo.NUM); //类.
// 代码编译时,会替换为:System.out.println(100);
}
}
说明:static final常量Foo.NUM会在编译时被替换为其常量值(100),在运行Goo类时,Foo类不需要被载入。这样减少了不必要的开支。
【顺序】
新建引用了一个子类时:
父类静态块
子类静态块
父类成员变量
父类构造方法
子类成员变量
子类构造方法
//通过类调用静态方法时,会先加载类 //Config.getIntValue("port");
//静态方法不会被加载
//静态块和静态成员变量按顺序加载,哪个在前面先运行哪个
//静态块内有方法的话,会运行这个方法
【抽象类】【抽象方法】
抽象方法:由abstract修饰的方法为抽象方法,抽象方法即只有方法的定义,没有方法体实现,用一个分号结尾。
即方法五要素中,抽象方法缺少了一个要素(即:方法体)。也可以将抽象方法理解为不完整的方法。
若将抽象方法包含在类中,则该类也应该为抽象的,可以理解为,该类也不完整。抽象类由abstract关键字声明。
抽象类是不能实例化对象的,而一个类不能实例化是没有意义的,所以,需要定义类来继承抽象类,而如果一个类继承了抽象类,
则其必须重写其抽象方法(变不完整为完整),除非该类也声明为抽象类。看下面的代码,定义了抽象方法和抽象类:
没有抽象方法,也可以生成抽象类
abstract class Shape {
private double c;
public Shape(double c) {
this.c = c;
}
public abstract double area();
}
通过上面的代码可以看到,area()方法没有方法体(连大括号也不存在),由abstract修饰,此为抽象方法。而Shape方法也由abstract修饰,即为抽象类。
【抽象类不可以实例化】
抽象类不可以实例化,若Shape是抽象类的话,下面的代码是错误的: 不可以创建对象,但可以创建数组 Shape[] s1 = new Shape[4];
// Shape s1 = new Shape(); //代码是错误的
即使一个类中没有抽象方法,也可以将其定义为抽象类,同样,该类不可以实例化。
需要注意一点:abstract和final关键字不可以同时用于修饰一个类,因为final关键字使得类不可继承,而abstract修饰的类如果不可以继承将没有任何意义。两者放在一起,会起冲突。
【设计原则】
1.只要是几个类共有的方法,就搞到父类中。
2.所有子类的工作(方法)都一样时用普通方法
所有子类都不一样时用抽象方法。
3.符合既是也是关系时,使用接口。
----接口是对继承单根性的扩展
【继承抽象类】
一个类继承抽象类后,必须实现其抽象方法,不同的子类可以有不同的实现。看下面的代码,Square类与Circle类
都继承自Shape类,并分别实现了重写的area()方法,只是其具体实现的代码不同:
class Square extends Shape {
private double c;
public Square(double c) {
super(c);
}
public double area() {
return 0.0625*c*c;
}
}
class Circle extends Shape{
private double c;
public Circle(double c) {
super(c);
}
public double area() {
return 0.0796*c*c;
}
}
【抽象类的意义】
定义抽象类的意义在于:
为其子类提供一个公共的类型(父类引用指向子类对象); 公共的入口
封装子类中的重复内容(成员变量和方法);
定义有抽象方法,子类虽然有不同的实现,但该方法的定义是一致的。(子类需要实现此抽象方法)。
看如下的代码:
Shape[] sArr = {new Circle(100), new Square(100),
new Circle(200), new Square(150) };
for(int i=0; i<sArr.length; i++) {
Shape shape = sArr[i];
System.out.println(shape.area());
}
通过上面的代码可以看出,以Shape类型的引用访问其子类,所有子类都会有area方法,只是其具体的实现各不一样。
【接口】 接口可以申明 成员变量 和int int[] 类一样
1)是一个标准,规范
实现了接口,就能干某件事-------API后就能体会
2)由interface定义
3)接口中只能包含常量(默认)和抽象方法(默认)
interface Inter{ //只有interface是默认public权限
public static final int NUM=5;
public abstract void show();
double Pi=3.14159; // 默认public static final
void say(); //默认public abstract
}
4)接口不能被实例化 //接口不能被实例化 抽象类不可以实例化
5)接口也需要被实现(继承)。实现类(子类)
5.1)必须实现接口中的所有抽象方法
class Aoo implements Inter{
public void show(){} //必须要加public 不然会默认为默认权限,而比父类的默认public权限小
//子类的访问权限大于或等于父类
}
6)继承只能继承一个类,但实现可以实现多个接口。用逗号分开,若又继承又实现接口时,必须先继承再实现
7)接口间可以继承(接口和接口叫继承,类和接口叫实现)
class AmericanCurl implements Runner , … {
public void run() {
System.out.println("run...");
}
}
另外需要说明的一点,接口可以作为一种类型声明变量,一个接口类型的变量可以引用实现了该接口的类的对象;
通过该变量可以调用该接口中定义的方法(具体的实现类提供了方法的实现)。代码如下所示:
Runner runner = new AmericanCurl();
此句代码为,一个接口类型变量,引用了子类的对象。调用时,调用的是子类对象的具体的实现。
抽象类和接口都不能实例化对象,用于被其他类继承和实现。
接口里只能包含抽象方法,抽象类则可以包含普通方法和抽象方法。
接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
一个类只能有一个直接父类;但一个类可以直接实现多个接口,实现多继承。
【接口和抽象类的区别】
抽象类和接口的区别:
1)一个类只能继承一个抽象类,但可以实现多个接口。
2)抽象类中可以包含抽象方法和非抽象方法,而接口中的所有方法均为抽象的。
3)子类继承抽象类必须实现抽象类中所有抽象方法,否则子类也必须是抽象类。而子类实现接口则必须实现接口中的所有抽象方法。
【oop】
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。
【多态】 //父类运行时指向不同的子类
优点:保证可维护性,实现低耦合
首先,一个类型的引用在指向不同的对象时会有不同的实现,看如下的代码:
达内职员 emp1 = new 达内讲师();
达内职员 emp2 = new 达内项目经理();
emp1.完成工作();
emp2.完成工作();
同样是达内职员类型,当指向不同的对象时,可以有不同的表现。
其次,同样一个对象,造型成不同的类型时,会有不同的功能,看如下代码所示:
达内讲师 teacher = new 达内讲师();
企业技术顾问 consultant = teacher; // teacher = new 达内讲师(); //teacher 达内讲师 类型
技术图书作者 author = teacher; // teacher = new 达内讲师(); //teacher 达内讲师 类型
consultant.培训员工();
author.编辑稿件();
通过上面的代码,可以看出,同样的达内讲师对象,当将其造型为企业技术顾问及技术图书作者时,可以实现不同的功能。
2.向上造型
1)能向上造型为:父类,实现的接口
2)能点出什么看类型
【数据类型转换】
1.自动类型转换:小类型转换到大类型
2.强制类型转换:大类型转换到小类型
引用类型:父类大,子类小
强制类型转换成功的条件
1)引用所指向的对象就是该类型
2)引用所指向的对象实现了该接口
强制类型转换失败会发生ClassCastException(类型转换异常)
所以在强转之前使用instanceof判断
Aoo o =new Boo();
Boo o1 =(Boo)o; //引用o所指向的对象(new Boo())就是该类型Boo //强制类型转换 看对象
Inter1 o2=(Inter1)o; //引用o所指向的对象(new Boo())实现了该接口
//Coo o3=(Coo)o; //编译错误 ClassCastException(类型转换异常)
instanceof返回boolean型结果,若true,则成功 // System.out.println(o instanceof Boo); //true 则成功
或if(o instanceof Boo){Boo o1=(Boo)o;}
interface Inter1{
}
class Aoo{
}
class Boo extends Aoo implements Inter1{
}
class Coo extends Aoo{
}
【内部类】 //内部类应用率比较低 //成员内部类
一个类可以定义在另外一个类的内部,定义在类内部的类称之为Inner内部类,其所在的类称之为Outer外部类;
Inter定义在Outer的内部,通常只服务于Outer,对外不具备可见性,
Inter可以直接调用Outer的成员及方法(包括私有的)。看如下代码:
class Outer{
private int time;
class Inner{
public void timeInc(){
time++;
}
}
}
内部类对象会在外部类中创建(构造方法或其他方法)
public class Line{
private Point p;
public class{
p=new Point(); // p=this.new Point();
}
public class Point{}
}
从上面的代码可以看出,在Outer类之中声明了Inner类,在Inner类中直接操作了Outer类的私有成员变量time。
内部类中也有独立的Outer$Inner.class //Mama$Baby.class
实例内部类
静态内部类,
局部内部类,
匿名内部类
package day28;
public class DemoClass {
class A{ //实例内部类
}
static class B{ //静态内部类
String name ="lisi";
void f(){
System.out.println(name);
}
}
public static void doClick(){
class C{ //局部内部类
String name ="zhangsan";
}
C c=new C(); //只能在局部内新建,在其他地方无法新建
System.out.println(c.name);
}
public static void main(String[] args) {
/*DemoClass d=new DemoClass(); //实例内部类
A a=d.new A();*/
A a=new DemoClass().new A();//实例内部类
B b= new DemoClass.B(); //静态内部类
//B b= new B(); //静态内部类
Runnable d = new Runnable() { //匿名内部类
@Override
public void run() {
// TODO Auto-generated method stub
}
};
}
}
【局部内部类】
final Thread ta =new Thread(){ } //局部内部类想访问方法内的变量时,要用final修饰。 //不是成员
【匿名内部类】 //应用率比较高
如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类),而且对象创建后,
这个类的价值也就不存在了,这个类可以不必命名,称之为匿名内部类。看下面的代码:
SuperType obj = new SuperType (…) {
… … …
};
其中,第一个SuperType为用匿名类所实现的接口或所继承的父类类型声明的引用;
第二个SuperType为匿名类所要实现的接口或继承的父类;小括号()中为构造方法参数;大括号中为匿名中定义的成员变量或方法。
请参见下面的代码:
public interface Action { //接口
public void execute(); //抽象方法
}
public class Main {
public static void main(String[] args) {
Action action = new Action(){
public void execute() {
System.out.println("Hello, World");
}
};
action.execute();
}
}
如上的代码中,创建了实现了Action接口的内部匿名类对象,并调用其execute方法。
匿名内部类中访问外部成员,该成员必须加final修饰
匿名内部类中也有独立的NstInnerDemo$1.class NstInnerDemo$2.class
面向对象
1)封装:保护数据
1.1)类---封装的对象的特征和行为
1.2)方法----封装的功能的具体的实现
1.3)访问修饰符----封装的是成员的访问权限
2)继承:代码的重用
2.1)所有子类所共有的特征和行为----父类中
特有的特征和行为----子类
2.2)继承后,子类具有自己特有的以及父类共有的
3)多态:
3.1)意义:
3.1.1)同一类型引用指向不同对象时有不同的实现
3.1.2)同一个对象被塑造为不同的类型时,有不同的功能
3.2)变现形式:重写,重载
3.3)向上造型
3.3.1)父类的引用指向子类的对象
3.3.2)能点出什么看类型
3.3.2)重写看对象
【字符串转换】 //字符串类型转换为其他类型
int choice=Integer.parseInt(scan.next()); //把字符串转换成int型整数 字符串整数
double num = Double.parseDouble(scan.next()); //把字符串转换成双精度浮点型 字符串双精度浮点型
String str = scan.next().trim().toUpperCase(); // if (str.equals("EXIT")) {break;}
char[] input = str.toCharArray(); //把字符串转换成char[]字符数组 字符串字符数组
byte[] date =str.getBytes(); //将当前字符串按照系统默认字符集转换为对应的字节数组 //搜索Stringbyte //可加("GBK")
String a=scan.nextLine();
【使用图片的类】
import java.awt.image.BufferedImage;
图片可以从外面直接拖进eclipse的包内
【随机整数】
import java.util.Random;
Random rand = new Random ();
x=rand.nextInt(ShootGame.WIDTH-this.width);
x=(int)(Math.random()*(ShootGame.WIDTH-this.width));
【JFrame】:窗口----相框
【JPanel】:面板
数据放在面板上
面板放在窗口上
import javax.swing.JFrame;
import javax.swing.JPanel;
【定时器】
private Timer timer; //定时器
private int intervel =10; //时间间隔(毫秒)
//静态,没有隐式this,与对象无关,与参数有关
public static FlyingObject nextOne(){ //工厂方法 //随机生成蜜蜂和敌机
Random rand =new Random();
int type=rand.nextInt(20);
if(type==0){ //蜜蜂的概率小
return new Bee();
}else{
return new Airplane();
}
}
int flyEnteredIndex=0;
public void enterAction(){ //10毫秒走一次
flyEnteredIndex++;
if(flyEnteredIndex%40==0){
FlyingObject obj=nextOne();
flyings=Arrays.copyOf(flyings, flyings.length+1); //扩容
flyings[flyings.length-1]=obj; //把新产生的敌人加到flyings数组的最后一个
}
}
public void stepAction(){
}
public void action(){
timer =new Timer();
//抽象类TimerTask的对象,不能直接new,因为是抽象的,所以用匿名内部类,
//第一个10指程序启动到第一次触发的间隔 //第二个10指第一次和第二次触发的间隔
timer.schedule(new TimerTask(){
//可以自动进行的程序放在run()里面。
public void run(){ //定时干的事(10毫秒走一次)
enterAction(); //敌人(敌机和小蜜蜂)入场
stepAction(); //飞行物走一步
}
}, intervel,intervel);
}
【paint()】方法的调用
1.frame.setVisible(true); //1.设置窗口可见 2.尽快调用paint()方法
2.repaint(); //重画(自动调用paint()方法)
【监听器】
private Timer timer; //定时器
private int intervel =10; //时间间隔(毫秒)
public void action(){ //运行一次
MouseAdapter l =new MouseAdapter(){ //【监听器】
public void mouseMoved(MouseEvent e){ //鼠标移动,就会进入这个程序
if(state==RUNNING){ //1
int x=e.getX();
int y=e.getY();
hero.moveTo(x, y); //英雄机坐标和鼠标坐标结合起来
}
}
public void mouseClicked(MouseEvent e){ //鼠标点击,就会进入这个程序
switch(state){
case START: //0
state=RUNNING; //1
break;
case GAME_OVER: //3
hero=new Hero(); //清理现场
flyings=new FlyingObject[0];
bullets=new Bullet[0];
score=0;
state=START; //0
break;
case RUNNING:
state=PAUSE;
break;
case PAUSE:
state=RUNNING;
break;
}
}
public void mouseExited(MouseEvent e){ //鼠标出去,就会进入这个程序
if(state==RUNNING ){ //1
state=PAUSE; //2
}
}
public void mouseEntered(MouseEvent e){ //鼠标进入,就会进入这个程序
if(state==PAUSE){ //2
state=RUNNING; //1
}
}
};
this.addMouseListener(l); //this 指代game //监听器放入面板
this.addMouseMotionListener(l);
timer =new Timer();
//抽象类TimerTask的对象,不能直接new,因为是抽象的,所以用匿名内部类,
//第一个10指程序启动到第一次触发的间隔 //第二个10指第一次和第二次触发的间隔
timer.schedule(new TimerTask(){ //定时器
//可以自动进行的程序放在run()里面。
public void run(){ //定时干的事(10毫秒走一次)
if(state==RUNNING){ //1
enterAction(); //敌人(敌机和小蜜蜂)入场
shootAction(); //子弹入场
stepAction(); //飞行物走一步
bangAction(); //敌人和子弹碰撞
outOfBoundsAction();//删除越界的敌人和子弹
checkGameOverAction(); //检查游戏是否结束
}
repaint(); //重画(自动调用paint()方法)
}
}, intervel,intervel);
}
事件:
1.鼠标移动事件:英雄机随之移动
mouseMoved
2.鼠标点击事件:启动状态变为运行状态
mouseClicked
3.鼠标移开事件:运行状态变为暂停状态
mouseExited
4.鼠标移入事件:暂停状态变为运行状态
mouseEntered
对面板操作
【颜色】 零
g.setColor(new Color(0xff0000));//0xff0000纯红色 0x0000ff蓝色 0x00ff00绿色
【文字】
Font font =new Font(Font.SANS_SERIF,Font.BOLD,14);//字体 加粗 大小
g.setFont(font);
第三本书
【API】
JAVA核心API(上)
JDK根据提供的功能不同,将类库划分为若干个包,
java.io包:比如用于操作输入输出的java.io包, //input output
java.lang:java程序语言设计基础类的java.lang包, //如:字符串,多线程。使用频率高不用导入,可以直接使用
java.math:提供各种数学运算的java.math包,
java.net:基于网络应用的java.net包,
java.util:以及一些共用程序类所在的java.util包等等。
java.security:安全相关操作
java.sql 数据库访问
java.text 处理文字,日期,数字,信息的格式
【文档注释】
/**.......*/ 文档注释 加在类和方法的开头,用于说明作者,时间,版本,要实现功能的详细描述等信息
通过javaoc工具,可以轻松的将此注释转换为HTML文档说明;学习者和程序员主要通过文档了解API的功能
(//..... 或 /*.... */) 普通注释
普通注释写在程序之中,用于程序员进行代码维护和交流,无法通过工具生成文档,而
文档注释写在类和方法的开头,专门用于生成供API使用者进行参考的文档资料
Export---Java---Javadoc---生成文档资料
【字符串类】 //lang包
【字符串】String不能被继承 //String学习
由于字符串在实际开发中被广泛使用,那么在频繁使用某个字符串时,会出现频繁创建一个字符串对象的现象,
java为此对字符串的使用采用了一个优化措施,使得String对象为不可变对象,一旦在内存中创建,内容不能发生变化,
若要对字符串内容改变,那么就会创建新对象。这样做的目的是可以最大程度的重用相同内容的字符串以减小系统资源的开销。
出于性能的考虑,JVM会将字符串直接量对象缓存在常量池中;对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回该对象。
如果是使用new关键字创建的字符串,则不会缓存在常量池中,使用new关键字将会创建新的String对象。
String str="HelloWorld"; //特权:字面量 直接量 引用类型String且不用new
int a=1;
String str1="HelloWorld";
String str2="HelloWorld";
System.out.println(str1==str2);
输出:true //str1,str2指向同一个对象,没有新建
str2=str2+"!"; //改变之后会新建一个字符串String
System.out.println(str1+" "+str2);
System.out.println(str1==str2);
输出:HelloWorld
HelloWorld!
false
String s1="123abc";
String s2="123abc";
String s3="123"+"abc"; //java编译器在编译代码时有个优化措施:当一个计算代表式中计算符两边的内容都是字面量
//编译器会将其进行运算然后将结果写入字节码文件中。所以下面的表达式在字节码文件中的样子是:
//String s3="123abc";
System.out.println(s1==s2); //true
System.out.println(s1==s3); //true
String s4=1+‘2‘+3+"abc"; //如果是“2”就等 //s4=54abc; //如果是1 + 2 + "3"+ "abc",则为33abc
System.out.println(s1==s4); //false
String s5="123";
String s6=s5+"abc"; //不是两边都是字面量,无法在编译时就计算
System.out.println(s1==s6); //false
if(s1.equals(s6)){ //true
System.out.println(123);
}
String s7=new String("123abc"); //直接新建一个,所以和原来的就不是同一个
System.out.println(s1==s7); //false
【length()】 //长度
String str ="我爱java";
System.out.println(str.length()); //字符长度 输出6
//数组的.length后面没有(),字符串的.length后面有()。
使用Java中的String类的length方法计算字符串的长度,无论中文还是英文都算1个长度。
另外,在Java中,字符在内存里采用的是Unicode编码,每个字符占用两个字节,请注意区别。
【indexOf()】 //通过字母找下标索引
int indexOf(String str)
* 查看给定字符串在当前字符串中的位置
* 若当前字符串中包含给定字符串,会返回给定字符串第一个字符在当前
* 字符串中的位置,若当前字符串不含给定字符串,则返回-1
String str ="thinking in java";
int index=str.indexOf("java"); //如果是in,则输出2
System.out.println(index);
输出12,从零开始,空格也算一个
//从下标(0123)是3,个数第四个字符开始寻找第一次出现in的位置
String str ="thinking in java";
int index=str.indexOf("in",3);
System.out.println(index); //输出5
【lastIndexOf()】
/**
* int lastIndexOf(str)
* 查找最后一次出现给定字符串的位置
* */
String str ="thinking in java";
int index=str.lastIndexOf("in");
System.out.println(index); //输出9
【substring()】 //获得 截取
/**
* String substring(int start,int end );
* 截取当前字符串中指定范围内的子字符串
* java API中,有一个特点
* 用两个数字表示范围时,通常是 //含头不含尾<=x<
* 下面的参数就是:包含11位置的字符,但不包含17位置的字符
* */
String str ="http://www.oracle.com";
String sub=str.substring(11,17); //只有11一个参数时,输出oracle.com
System.out.println(sub); //输出oracle
可以只填一个 //只有11一个参数时,输出oracle.com
String sub=str.substring(11);
/**
* 获取一个URL的域名
* 思路:截取地址中第一个“.”与第二个"."之间的字符串即可
* 步骤:
* 1.找到第一个"."的位置
* 2.找到第二个"."的位置
* 3.截取第一个点后面的第一个字符开始,到第二个点的位置的所有字符
*/
String url="http://www.tarena.com.cn";
int start =url.indexOf(".");
int end =url.indexOf(".",start+1);
String name=url.substring(start+1,end);
System.out.println(name); //输出tarena
最后一个“/”后的所有字符
String str="someapp/manager/emplist.action";
int index=str.lastIndexOf("/");
String sub=str.substring(index+1,str.length());
System.out.println(sub); //输出:emplist.action
【trim()】 //去掉左右两边“空白”,中间的不会去除
/**
* String trim();
* 该方法就是将当前字符串中左右两边的“空白”去掉,中间的不会去除
* trim方法一般用于去除用户输入信息中的前后空白以及处理文件内容时,去除文件中的空白。
* */
String str=" hel lo ";
String trim=str.trim();
System.out.println(str);
System.out.println(trim);
输出:
hel lo
hel lo
【charAt()】 //通过下标索引找字母
/**
* char charAt(int i);
* 返回当前字符串中给定位置处对应的字符
* */
String str ="thinking in java";
char c=str.charAt(9);
System.out.println(c); //输出i
/**
* 检查一个字符串是否为“回文”;
* */
String str= "上海自来水来自海上";
for(int i=0;i<str.length()/2;i++){
if(str.charAt(i)!=str.charAt(str.length()-i-1)){
System.out.println("不是回文");
return; //返回,不再执行下面的部分,前提是返回值为void。也可以用开关来设定
}
}
System.out.println("是回文");
【startsWith()】【endsWith()】 //判断以什么开头,以什么结尾
/** boolean startsWith(String str)
*判断当前字符串是否是以给定字符串开始的
*
*boolean endsWith(String str)
*判断当前字符串是否是以给定字符结束的
*/
String str ="thinking in java";
boolean starts=str.startsWith("th");
System.out.println("starts:"+starts);
boolean ends=str.endsWith("ava");
System.out.println("ends:"+ends);
输出:
starts:true
ends:true
【toUpperCase()】【toLowerCase()】 //大小写
/**
* String toUpperCase()
* 将当前字符串中的英文部分转换为全大写
* String toLowerCase()
* 将当前字符串中的英文部分转换为全小写
* 常被用于检查字符串中英文部分,完成忽略大小写操作
* */
String str="我爱Java";
String upper =str.toUpperCase();
System.out.println(upper);
String lower =str.toLowerCase();
System.out.println(lower);
输出:
我爱JAVA
我爱java
【valueOf()】 //其他类型转换为字符串类型
/**
* 字符串提供了若干的重载静态方法valueOf()
* 通常用来将其他类型转换为字符串形态
* @author tarena
* */
* int i=100;
String s1=String.valueOf(i); //String s3=i+"";同样可以整型转换成字符串
System.out.println(s1);
* double d=1000.123;
String s2 =String.valueOf(d); //浮点型转换为字符串
System.out.println(s2);
* String str3=new String(字节数组,0,n); //将字节数组中的所有字节转换为对应的字符串
* char[] a={‘a‘,‘b‘,‘v‘,‘g‘,‘d‘};
String s2 =String.valueOf(a); //字符数组转换为字符串 方法0
System.out.println(s2);
* String s3=new String(字符数组); //字符数组转换为字符串 方法一
char[] a={‘a‘,‘b‘,‘v‘,‘g‘,‘d‘}; //字符数组转换为字符串 方法二
String s="";
for (int i = 0; i < a.length; i++) {
s+=a[i];
}
System.out.println(s); //abvgd
char[] a={‘a‘,‘b‘,‘v‘,‘g‘,‘d‘};
StringBuilder sb=new StringBuilder();
for (int i = 0; i < a.length; i++) {
sb.append(a[i]); //字符数组转换为字符串 方法三
}
String s=sb.toString();
System.out.println(s); //abvgd
*Arrays.toString(a1) //数组转换成字符串
【StringBuilder】
* StringBuilder用于解决修改字符串导致的内存消耗问题
* StringBuilder内部维护一个可变的字符数组,所以修改的
* 字符串内容都是在当前对象中完成,而不会创建新对象
* StringBuilder提供了修改字符串的相关方法:增删改插
* */
StringBuffer有如下常用构造方法: //不懂
public StringBuilder()
public StringBuilder(String str)
构造方法StringBuffer()将创建不包含任何字符序列的StringBuilder对象 //可变 //安全
而StringBuilder(String str)将创建包含参数字符串str的StringBuilder对象 //可变 //不安全,但很方便
String //String不可变
String str ="好好学习java";
StringBuilder builder=new StringBuilder(str);
/**
* 获取StringBuilder表示的字符串
* String toString();
* */
str =builder.toString();
System.out.println(str); //输出:好好学习java
/**
* StringBuilder append(String str)
* 该方法用于向当前字符串末尾追加给定字符串
* 返回值还是当前StringBuilder
* */
builder.append(",为了改变世界!"); //追加
str =builder.toString();
System.out.println(str); //输出:好好学习java,为了改变世界!
/**
* StringBuilder insert(int i,String str);
* 在当前字符串的指定位置插入给定字符串,
* 原位置及后续字符串顺序向后移动
* */
builder.insert(9,"就是"); //插入
str =builder.toString();
System.out.println(str); //输出:好好学习java,就是为了改变世界!
//活着,就是为了改变世界!
/**
* StringBuilder replace(int start,int end,String s );
* 将当前字符串中指定范围内的字符串替换为给定的字符串 //含头不含尾
* */
builder.replace(0, 8, "活着"); //替换
str =builder.toString();
System.out.println(str); //输出:活着,就是为了改变世界!
//活着,就是为了改变世界
/**
* StringBuilder delete(int start,int end);
* 删除当前字符串中指定范围的字符串
* */
builder.delete(11, 12); //删除
str=builder.toString();
System.out.println(str); //输出:活着,就是为了改变世界
/**
* reverse();
* 将当前字符串内容反转
* */
builder.reverse(); //反转
str=builder.toString();
System.out.println(str); //输出:界世变改了为是就,着活
例子:
String str= "上海自来水来自海上";
StringBuilder builder=new StringBuilder(str);
builder.reverse();
String str1 =builder.toString();
if(str.equals(str1)){
System.out.println("是回文");
}else{
System.out.println("不是回文");
}
System.out.println(str==str1);
输出:
是回文
false
【基本正则表达式】 //
验证一个字符串满不满足格式要求(只关注格式,不关注有没有校)
转意字符: +(加号) \(斜杠) .(小数点) 需要加\(斜杠) 输入两次输出一次
1、“.”和"\"
"."点儿,在正则表达式中表示任意一个字符。
"\"在正则表达式中是转意字符,当我们需要描述一个已经被正则表达式使用的特殊字符时,我们就可以通过使用"\"将其转变为原本的意思。
"\"在正则表达式中也有一些预定义的特殊内容:
\d:表示任意一个数字
\w:表示任意一个单词字符(只能是 数字,字母,下划线)
\s:表示任意一个空白字符(\t \r \n \f \x0B)
\D:表示任意一个非数字字符
\W:表示任意一个非单词字符
\S:表示任意一个非空白字符
2、"字符集合 []"
"[]"用来描述单一字符,方括号内部可以定义这个字符的内容,也可以描述一个范围。例如:
[abc]:表示该字符只能是a或者b或者c
[123]:表示该字符只能是1或者2或者3
当我们需要描述所有小写字母时,我们可以使用范围 [a-z],表示该字符可以是任意一个小写字母。
同样还可以使用 [0-9] 来表示该字符可以是任意一个数字。
也可以在多个范围内选择。比如,[a-zA-Z0-9_] 表示该字符可以是任意字母,数字以及"下划线"。
[a-z&&[^bc]]a到z中除去bc的字母 除了^
3、"*"、"+"、"?"
通常我们需要描述的字符串会有很多重复出现的元素,但又不需要严格限制出现的次数时,我们就可以使用"*","+"这些量词。
例如:邮箱地址,那么在"@"字符前允许出现若干字符作为用户名。这时候我们就可以使用"\w+"来描述这里至少出现一个单词字符了。
"+":表示内容可以连续出现至少1次以上
"*":表示内容出现0-若干次
"?":表示内容出现0-1次
4、{n}、{n,}{n,m}
除了前面讲到的量词外,有时我们也需要要求内容出现的次数有具体要求。比如手机号码。这时我们要求出现的数字就不能是一个模糊的概念了,
而必须要求11位。又比如我们要求用户输入密码时,要求密码是6-15位。遇到这类问题是,我们可以使用:
{n}:表示内容必须出现n次
{n,m}:表示内容出现n-m次
{n,}:表示内容出现至少n次
例如,\d{11} 就表示数字只能出现11位,这样就解决了上述的问题。
【0-9】{0,6}//0到6次 不能是负数
【0-9】{6,} //6到无数次
[abc]{3} //aaa //abc //acb
(abc){3} //abcabcabc
^[abc]{3}$ //只能是abc,不能加其他的东西 ^表示开始 $表示结尾
5、分组
通过上面的内容,我们还无法解决类似下面的问题:
在描述电话号码时,前面有区号,区号的形式可以是0086或者+86
那么我们如何在这两个字符串之间选择?
这时我们可以使用分组"()"。() 可以将内容看做一个整体,()中可以使用"|"来表示或关系。例如,(+86|0086) 表示这里可以是+86或者0086。
6、 "^ "和"$"
通过在正则表达式的开始添加"^"以及末尾添加"$"来表示一个整体。若不使用它们,那么正则表达式只匹配某个字符串的部分内容是否符合格式规则,
但使用它们,则要求字符串必须从头到尾都满足该格式规则。例如,^\w{ 8,10 }$ 表示整体字符串只能出现单词字符8-10个。
检索邮政编码 规则为6位数字
【0-9】【0-9】【0-9】【0-9】【0-9】【0-9】 //方法一
\d\d\d\d\d\d //方法二
\d{6} //方法三 "^[1-9][0-9]{5}$";
验证身份证号码的正则表达式 //[0-9]{15}([0-9]{2}[0-9]xX)
private static final String IDENTITY_CARD = "^\\d{15}|\\d{18}$";
匹配手机号码前面的区号 例子: +86 13838389438
(\+89|0086)?\s*\d{11} //String sssString="(\\+89|0086)?\\s*\\d{11}";
\+:转意字符,匹配+号
?:前面的组可有可无
\s:空白字符
*:前面的字符数量>=0
\d:数字字符
{11}:前面的字符数量为11位
匹配用户名规则,从头到尾连续8-10个单词字符 \w 表示[a-zA-Z0-9_]
\w{8,10} //abcd1234_abcd可以通过
^\w{8,10}$ //abcd1234_abcd不可以通过
【matches】 //整体比较 //正则表达式放在括号内
matches()方法的参数要求我们传入一个用字符串描述的正则表达式,然后使用该正则表达式描述的字符串格式规则来匹配当前字符串,
若满足那么该方法返回true。否则返回false。
例子:
String regex="[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\\.[a-zA-Z0-9]+)+"; //要比较. 要输出\. 则要输入\\. // \.编译错误
System.out.println(regex);
String str ="fancq@tarena.com.cn";
boolean matches=str.matches(regex);
System.out.println(matches?"是邮箱":"不是邮箱");
输出:
[a-zA-Z0-9_]+@[a-zA-Z0-9_]+(\.[a-zA-Z0-9]+)+
是邮箱
例子:
String sssString="(\\+89|0086)?\\s*\\d{11}"; //"([+][8][9]|0086)?\\s*\\d{11}";//"^(13)[0-9]{9}|15[89][0-9]{8}$";
System.out.println(sssString);
String str ="+89 13456987120";
boolean matches=str.matches(sssString);
System.out.println(matches?"是电话号码":"不是电话号码");
输出:
(\+89|0086)?\s*\d{11}
是电话号码
【split】方法 //拆分
String[] split(String regex):参数要求传入一个用字符串描述的正则表达式,然后使用该正则表达式描述的字符串规则来匹配当前字符串,并按照满足的部分将字符串拆分。
/**
* 切掉所有数字部分,只保留所有英文部分
* */
String str ="asdfa4544sfg556fh5sfh5sg5sh";
StringBuilder s=new StringBuilder();
String[] arr =str.split("[0-9]+");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]); //asdfasfgfhsfhsgsh //把数字给拆没了
s.append(arr[i]);
}
System.out.println();
str=s.toString();
System.out.println(str); //改为了字符串asdfasfgfhsfhsgsh
String str1 ="1\\2\\3\\4\\5\\6\\7\\8\\9\\0"; //为一条斜杠
String[] arr1=str1.split("\\\\"); //为两条斜杠
for (int i = 0; i < arr1.length; i++) {
System.out.print(arr1[i]);
}
System.out.println();
输出:1234567890
String str2="1,2,3,4,5,6,7,8,9";
/**
* 如果,在字符串前面,中间,连续出现了若干次要拆分的字符,那么每一项中间都会拆除一个空字符
* 例如:,,,,,1,2,3,4,,,,,5,6,7
* 在1之前,会拆出5个空字符串,中间也是
* 如果在后面的话,不会拆出空字符串 //1,2,3,,,,,,
* */
String[] arr2=str2.split(",");
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i]);
}
System.out.println();
String imgName="2015/04/03.jpg";
String[] arr3=imgName.split("\\."); //如果填. 则代表所有字符,会把所有字符都删掉
long c=System.currentTimeMillis();
imgName=c+"."+arr3[1];
System.out.println(imgName);
【replaceAll】方法 //替换
String replaceAll(String regex,String replacement):参数要求传入一个用字符串描述的正则表达式和
一个需要替换的字符串,然后使用该正则表达式描述的字符串规则来匹配当前字符串,并将满足的部分替换为需要替换的这个字符串。
String str="sdg545sf65s4dg5s5f4gs54gs5dg";
/**
* 将字符串中的数字部分替换为字符串“#NUMBER”
* */
System.out.println(str);
str =str.replaceAll("[0-9]+", "#NUMBER");
System.out.println(str);
String regex = "(wqnmlgb|cnm|sb|fuck|nmd)";
String message="wqnmlgb,你怎么搞得,sb.";
message =message.replaceAll(regex, "****");
System.out.println(message);
【Pattern】 //封装正则表达式 //重点是Matcher //有一个例子
【Matcher】 //封装正则表达式和要匹配的字符串
一次次向后查看下一段匹配的子串
Pattern p0= Pattern.compile("[0-9]+"); //创建对象 //不能直接new
Matcher m0 =p0.matcher("good good study"); //创建对象 //还是不能new
//find();方法 //向后查找下一对匹配的子串 ,返回boolean值,表示是否找到字串
//group();方法 //返回刚刚找到的子串
//start();方法 //返回刚刚找到的起始位置 含头不含尾
//end();方法 //返回刚刚找到的结束位置 含头不含尾
System.out.println("输入"); //输入sgshsf2654646gbigjk56454531
String s =new Scanner(System.in).nextLine();
Pattern p =Pattern.compile("\\d{3,}"); //创建对象
Matcher m =p.matcher(s);
while(m.find()){ //一次次向后查看下一段
String tel =m.group(); //取出找到的字串 //可放在end下面
int start =m.start(); //起始位置
int end =m.end(); //结束位置
System.out.println(start+","+end+":"+tel); //6,13:2654646 //19,27:56454531
【Object】任何一个类在最终都会继承Object类
【toString()】 //返回一个字符串
package day02;
public class StringDemo06 {
public static void main(String[] args) {
/**
* String toString()
* 该方法要求返回一个字符串
* Java希望我们定义的类若需要使用toString该方法时,就重写该方法
* Object中的实现返回的字符串格式位:类型@地址
* */
point p =new point();
p.x=1;
p.y=2;
String string =p.toString();
System.out.println(string); //重写toString之前day02.point@868c6d //重写toString之后(1,2)
/**
* System.out.println(Object o)
* 该方法会将给定的对象的toString方法返回字符串输出到控制台
* */
System.out.println(p); //(1,2)
}
}
class point {
public int x;
public int y;
public String toString(){
return "("+x+","+y+")"; //输出(1,2)
}
public boolean equals(Object o){
if(o==null){ //空
return false;
}
if(o==this){ //他自己
return true;
}
if(o instanceof Point){ //if (obj instanceof Emp) {
Point p=(Point)o; //Emp emp = (Emp) obj;
/**
* 比较两个对象的属性内容是否一致
* 这里参与的属性要结合实际需求
* 当前例子:x,y都一样
* */
return this.x==p.x&&this.y==p.y; //都是整形 //return this.name.equals(emp.name); //字符串
}
return false;
}
}
【equals】 //等于
Point p1=new Point();
p1.x=1;
p1.y=2;
boolean t=p.equals(p1);
System.out.println(t); //true
【包装类】 //
我们知道java是面向对象的语言,其精髓之一是可以使用多态性,提高程序的灵活度。
但是java中有8个基本类型:byte,short,int,long,float,double,char,boolean。它
们是以值的形式存在于内存中,而不是对象。它们不是Object的子类,不能参与面向对象的开发。
在java1.5版本以前以下的代码是不能通过的
public class Test{
public static void main(String[] args){
String str = "hello";
doSome(str);//可以,因为String是Object的子类
int i = 1;
//程序编译不通过,原因在于int不是Object的子类,不能使用多态性。
doSome(i);
}
public static void doSome(Object o){
....
}
}
问题出现的原因就是基本类型int没有继承关系,它不是Object的子类。所以,若想让基本类型以对象的形式存在,
我们就需要定义一个类Integer,然后用其实例来描述一个基本类型int。这样的好处在于,我们使用对象来描述基本类型数据,
而类又是继承自Object的。从而可以让基本类型参与面向对象的开发。好在,像Integer这样的类不需要我们定义,因为java已经提供了8中基本类型对应的包装类。
注:java1.5版本后出现了自动拆装箱特性,上述代码可以正常编译通过。自动拆装箱我们后面会详细描述。
对于8个基本类型,java提供了他们相应的包装类:
基本类型 包装类
byte java.lang.Byte //父类java.lang.Number //Byte
short java.lang.Short //父类java.lang.Number //Short
int java.lang.Integer //父类java.lang.Number //Integer
long java.lang.Long //父类java.lang.Number //Long
float java.lang.Float //父类java.lang.Number //Float
double java.lang.Double //父类java.lang.Number //Double
char java.lang.Character //父类java.lang.Object //Character
boolean java.lang.Boolean //父类java.lang.Object //Boolean
其中除了Character与Boolean的父类是Object之外,其余的都是继承自:java.lang.Number
【intValue()】 //将当前对象表示的数字以基本类型的int值返回
/**
*int intValue()
*将当前对象表示的数字以基本类型的int值返回
*
* double doubleValue()
* 将当前独享表示的数字以基本类型的double值返回
* */
1.Integer a=new Integer(10);
2.Integer a=Integer.valueOf(10);
Double doub =new Double(1.2); //定义double类型的包装类
double d=doub.doubleValue();
System.out.println(d); //1.2
//还可以转换为其他基本数据类型,不过可能会丢失精度
int i=doub.intValue();
System.out.println(i); //1
byteValue
shortValue
intValue
longValue
floatValue
doubleValue
【MAX_VALUE】【MIN_VALUE】 //最大值 最小值
/**
* 数字包装有两个常量
* max min
* */
int max=Integer.MAX_VALUE;
int min=Integer.MIN_VALUE;
System.out.println(max); //2147483647
System.out.println(min); //-2147483648
【Integer常用功能】【parseInt】【parseDouble】 //将字符串转换为对应的基本类型
/**
* 包装类最常用的一个方法
* 数字包装类有一个静态方法:parseXXX()
* 可以将字符串转换为对应的基本类型
* */
Integer.parseInt("255"); //255
Integer.parseInt("ff",16); //16进制 //255
Integer.parseInt("377",8); //8进制 //255
Integer.parseInt("11111111",2); //2进制 //255
String str ="123";
int i=Integer.parseInt(str); //str必须是整数,不能是小数,或有字母汉字
System.out.println(i); //123
double d =Double.parseDouble(str);
System.out.println(d); //123.0
【Double】//对特殊值进行检查的方法
Double.isInfinite(double d);
Double.isNaN(double d);
【BigDecimal】 //大数值//做精确的浮点数运算 //加减乘数+-*/ //高精度
【BigInteger】 //做超出长整形范围的整数运算 //超过long //超出long
BigDecimal bd =BigDecimal.valueOf(3.14);
add(BigDecimal bd) //+
subtract(BigDecimal bd) //-
multiply(BigDecimal bd) //*
divide(BigDecimal bd) // /
divide(BigDecimal bd,小数位数,舍入方式) // /方法的重写 //
舍入方式 BigDecimal.ROUND_HALF_UP ; BigDecimal.ROUND_UP ; BigDecimal.ROUND_DOWN
设置舍入方式 setScale(小数位数,舍入方式)
例子:+-*/
System.out.println("输入");
double a=new Scanner(System.in).nextDouble(); //输入15.5
double b=new Scanner(System.in).nextDouble(); //10
BigDecimal bd =BigDecimal.valueOf(a);
BigDecimal bed =BigDecimal.valueOf(b);
System.out.println("a+b:"+bed.add(bd)); //a+b:25.5
System.out.println("a-b:"+bed.subtract(bd)); //a-b:-5.5
System.out.println("a*b:"+bed.multiply(bd)); //a*b:155.00
System.out.println("a/b:"+bed.divide(bd,10,BigDecimal.ROUND_HALF_UP)); //a/b:0.6451612903
对一个浮点数,四舍五入保留小数点后2位 : //设置舍入方式 setScale(小数位数,舍入方式)
double a=2.45665;
BigDecimal bd =BigDecimal.valueOf(a);
BigDecimal aa=bd.setScale(2,BigDecimal.ROUND_HALF_DOWN);
//double cc=aa.doubleValue(); System.out.println(cc); //转换为double浮点型
System.out.println(aa);
【DecimalFormat】 //格式字符串
DecimalFormat f =new DecimalFormat(格式字符串); //格式字符串
//方法:format(数字) //数字格式化成字符串
//方法:parse(字符串) //字符串转换成数字
//方法:setPattern(格式) //修改格式
System.out.println("输入数字");
double a =new Scanner(System.in).nextDouble(); //输入152
DecimalFormat f =new DecimalFormat("\u00A4###,###.000");
String s =f.format(a);
System.out.println(s);//¥152.000
Number n=f.parse(s);
a=n.doubleValue();
System.out.println(a); //152.0
$###,###.000 //将数据格式化为每三位一个逗号,保留三位小数
【自动装箱和拆箱操作】【valueOf】
Integer inte =Integer.valueOf(1); //将基本类型转换为包装类
Integer inte =1; //JVM依然不认可,但5.0之后编译器默认加上Integer.valueOf(1); 自动装箱特性
int i1=inte; //JVM依然不认可,但5.0之后编译器默认加上inte.intValue(); 自动拆箱特性
Integer a = 100 => Integer a = Integer.valueOf(100);
Integer b = 200 => Integer b = Integer.valueOf(200);
Integer c = a+b => Integer c = Integer.valueOf (a.intValue( ) + b.intValue( ));
double d = c => double d = c . doubleValue( );
/**
* 基本类型转换为包装类时建议使用
* 静态方法 valueOf() ////equals比较封装的值 //==比较地址
* */
Integer i1=Integer.valueOf(129); //推荐使用这种方法 //如果封装的数值是-128到127,会从Integer对象缓存区获得已经存在的对象
Integer i2=Integer.valueOf(129); //否则,会新建一个对象
System.out.println(i1==i2); //false 小于等于127的话是true
System.out.println(i1.equals(i2)); //true
Integer i3=new Integer(2);
Integer i4=new Integer(2);
System.out.println(i3==i4); //false 只要new了就一定会新建,不会相等
System.out.println(i3.equals(i4)); //true
Integer d= Integer.valueOf(255); //255的2进制为 11111111
System.out.println(d.byteValue()); //-1 //byte一字节八位,就变成-1
System.out.println(d.shortValue()); //255
System.out.println(d.intValue()); //255
System.out.println(d.longValue()); //255
System.out.println(d.floatValue()); //255.0
System.out.println(d.doubleValue()); //255.0
【时间类】
【JAVA 中的时间】
Java中的时间使用标准类库的Date类表示,是用距离一个固定时间点的毫秒数(可正可负,long类型)表达一个特定的时间点。
固定的时间点叫纪元(epoch),是UTC时间1970年 1月 1日 00:00:00。
UTC(Universal Time Coordinated世界调整时间)与GMT(Greenwich Mean Time格林威治时间)一样,是一种具有实际目的的科学标准时间。
【Date类】简介 // x之后点击推荐的第二个类 //不能导入sql,要导入util包
java.util.Date 类封装日期及时间信息。
Date类的大多数用于进行时间分量计算的方法已经被Calendar取代。查看如下代码:
Date date = new Date();
// 系统当前的日期及时间信息
System.out.println(date);
// Sun Jan 06 11:52:55 CST 2013
long time = date.getTime();
//1970年1月1日至今的毫秒数
因为Date的设计具有"千年虫"以及"时区"的问题,所以Date中的大部分方法已经不建议使用了,它们都被java.util.Calendar类所取代,该类我们稍后会讲解。
【显示时间】【Date】选推荐的第二个类
import java.util.Date;
/**
* java.util.Date
* 该类内部维护一个long值,表示从1970年元旦到要描述的时间之间所经过的毫秒值
* 由于Date的设计缺陷,现在仅用它表示时间,而不做时间相关的其他操作
* */
Date date =new Date(); //x之后推荐的第二个类 //新建一个
System.out.println(date); //输出Tue Apr 07 10:34:31 CST 2015
/**
* long getTime()
* 获取当前Date内部维护的long值
* 即:1970年元旦到描述的时间点之间的毫秒值
* */
获取毫秒数
long time =date.getTime();
System.out.println(time); //毫秒值 //1428374852902
time +=1000*60*60*24; //在编译器内已经算完了,在class内就是结果//加一天的毫秒数
/**
* void setTime(long time)
* 将给定的毫秒值设定到当前的Date对象中,使其表示该时间
* */
毫秒转到时间 第一种
date.setTime(time);
System.out.println(date); //输出:Wed Apr 08 10:47:32 CST 2015
毫秒转到时间 第二种
long last =111111111111111L; //file.lastModified();
Date date=new Date(last);
System.out.println(date);//5490-12-21
【SimpleDateFormat】【sdf.format()】【sdf.parse()】 //2015-04-07 11:05:03
/**
* 该类的主要作用:
* 将Date转换为字符串
* 将字符串转换为Date
* 在两者之间进行转换是需要指定格式的
* 而格式也需要一个字符串描述
* */
Date now = new Date(); //当前系统时间
//Date的toString
System.out.println(now); //Tue Apr 07 11:05:03 CST 2015
/**
* 希望输出的字符串样式:
* 2015-04-07 11:00:58
* yyyy-MM-dd HH:mm:ss
* */
英文习惯的时间改成中文习惯的字符串时间
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String str1=sdf.format(now); //sdf.format()
System.out.println(str1); //输出:2015-04-07 11:05:03 星期
把字符串改为英文习惯的时间
String str="2008/08/08 20:08:08";
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
/**
* Date parse(String str)
* 将给定的字符床按照SimpleDateFormat指定的日期
* 格式解析为时间并用Date表示
* */
把字符串改为英文习惯的时间
Date date=sdf.parse(str); //点第二个 //sdf.parse()
System.out.println(date); //输出:Fri Aug 08 20:08:08 CST 2008
String ss="00:00:11";
SimpleDateFormat sdf =new SimpleDateFormat("HH:mm:ss");
long dateStart=sdf.parse(ss).getTime()+28800000; //时区带来的8小时
System.out.println(dateStart );
【日历类】
/**
* Calender 日历类
* 用于操作时间的类
* 本身是抽象类不能实例化,常用的是封装了格里高利历法的实例类
* 就是所谓的阳历
* 其提供了一个静态方法,用于获取一个适当的实现类
* java.util.Calendar;
* 默认创建出来的也是表示当前系统时间
* */
创建一个
Calendar calendar=Calendar.getInstance(); //不推荐 Calendar calendar=new GregorianCalender();使用的是罗马历,公历
System.out.println(calendar); //Calendar重写了toString,不可读
/**
* Date getTime()
* 该方法用于获取一个Date对象,该对象表示时间
* 就是当前Calender所表示的时间
* */
获得时间
Date date2=calendar.getTime();
System.out.println(date2);
System.out.println(calendar.getTimeInMillis());//1422813722812 获得毫秒数
calendar.setTimeInMillis(time); //通过毫秒数设定时间,还是calendar类型
/**
* void setTime(Date date)
* 使当前Calendar表示给定的Date所表示的时间
* */
设定时间 //设置时间
calendar.setTime(date2); //setTimeInMillis() //设定毫秒数
/**
* String,Date,Calender之间的相互转换
* String->Date
* 借助于SimpleDateFormat的parse()方法
*
* Date->String
* 借助于SimpleDateFormat的format()方法
*
* Date->Calender
* 使用Calender的setTime()方法
*
* Claender->Date
* 使用Calender的getTime()方法
* */
/**
* Calender设置时间
* 可以对当前Calender的不同时间单位进行分别的设置
* 使得其可以表示给定的时间
* */
/**
* void set(int field,int value)
* 对给定时间分量(单位)设置给定的值
* */
Calendar calendar2=Calendar.getInstance();
/**
* 当我们对某个时间分量设置新值后,通常年月日时分秒能不变的就不变,
*但有些情况也是要受到牵连而跟着变化,比如星期几
* */
设置年份
calendar2.set(Calendar.YEAR, 2008); //设置年,星期可能会跟着改变
System.out.println(calendar2.getTime());
/**
* 设置为10月
* 月份的值有常量对应
* 若学数字需要注意:0表示1月,以此类推11表示12月
* */
设置月份 //输入10,输出11月 //星期设定3,才是周2
calendar2.set(Calendar.MONTH, 10);
System.out.println(calendar2.getTime());
SimpleDateFormat sdf0 =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String str0=sdf0.format(calendar2.getTime()); //sdf.format()
System.out.println(str0); //输出:2008-11-07 15:05:36 星期五
/**
* 设置日
* 8号
* DATE:月中的天 几号
* DAY_OF_MONTH:与DATE等价
*
* DAY_OF_WEEK: 星期中的天 星期几
* DAY_OF_YEAR:年中的天
* */
//设置日
calendar2.set(Calendar.DAY_OF_MONTH, 8);
System.out.println(calendar2.getTime());
/**
* 设置时
* HOUR:12小时制
* HOUR_OF_DAY:24小时制
* */
//设置时
calendar2.set(Calendar.HOUR_OF_DAY, 20);
calendar2.set(Calendar.MINUTE, 8);
calendar2.set(Calendar.SECOND, 8);
System.out.println(calendar2.getTime()); //Sat Nov 08 20:08:08 CST 2008
String str00=sdf0.format(calendar2.getTime()); //sdf.format()
System.out.println(str00); //2008-11-08 20:08:08 星期六 星期自动变不用设置
今天是某年某月某日星期几 一年的第多少天
/**
* 获取当前Calendar表示的时间中某个时间分量对应的值
* int get(int field)
* */
Calendar calendar =Calendar.getInstance();
//获取年
int year =calendar.get(Calendar.YEAR);
System.out.println(year); //2015年
//获取月
int month =calendar.get(Calendar.MONTH);
System.out.println(month+1); //4月
//获取日
int day =calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day); //7日
//今年的第几天
int day1 =calendar.get(Calendar.DAY_OF_YEAR);
System.out.println(day1); //今年的第97天
//今天星期几
int dow =calendar.get(Calendar.DAY_OF_WEEK);
System.out.println(dow==1?7:dow-1); // 星期2
一年共365天
/**
* 截取某个时间分量所允许的最大值
* */
/**总是以当前Calender所表示的时间作为基准,看给定的时间分量
* 所允许的最大值
* */
Calendar calender=Calendar.getInstance();
int days=calender.getActualMaximum(Calendar.DAY_OF_YEAR);
System.out.println(days); //共365天
时间的计算方法
/**
* 时间的计算方法
* void add(int field,int value)
* 对给定的时间分量累加给定的值,若值为负数,就减
* */
Calendar calendar =Calendar.getInstance();
/**
*2年3个月零15天以后的那周的周二是几号
* */
calendar.add(Calendar.YEAR, 2);
calendar.add(Calendar.MONTH, 3);
calendar.add(Calendar.DAY_OF_YEAR, 15); //加天的时候用DAY_OF_YEAR,因为可能会跨年
System.out.println(calendar.getTime());//Sat Jul 22 15:58:40 CST 2017
calendar.set(Calendar.DAY_OF_WEEK, 3); //设定3,才是周2
System.out.println(calendar.getTime());//Tue Jul 18 15:58:40 CST 2017
【集合接口】
Collection
java提供了一种可以存数一组数据的数据结构,其提供了丰富的方法,在实际开发中往往比数组使用的广泛。这种数据结构成为集合:Collection。
Collection是一个接口,其定义了集合的相关功能方法。
【List】 实现类ArrayList LinkedList
【Set】 实现类HashSet TreeSet
Collection派生出了两个子接口,一个是List另一个则是Set。
List:称为可重复集,顾名思义,该集合中是允许存放重复元素的,那么何为重复元素?重复元素指的并非是同一个元素,而是指equals方法比较为true的元素。//有序
Set:称为不可重复集,所以,该集合中是不能将相同的元素存入集合两次,同List,这里相同指的也是两个元素的equals比较结果为true。 //大部分无序
集合持有对象的引用
集合中存储的都是引用类型的元素,那么引用类型变量实际上存储的是对象的“地址”,所以实际上集合只存储了元素对象在堆中的地址。而并不是将对象本身存入了集合中。
如果只在两端操作数据,选择LinkedList
只要会操作中间的数据,就用ArrayList
List:访问两端效率高
/**
* java.util.Collection
* 集合用于存放一组元素
* 其定义了用于操作集合元素的相关方法
* 通常我们存放一组元素使用集合而不是数组
* */
//创建List集合
Collection c = new ArrayList();
/**
* boolean add(E e)
* 向集合中添加给定的元素
* 添加成功返回true,否则返回false
* 集合虽然什么类型的实例都可以放,但实际使用时还是大部分情况还是只存放一种类型的元素
* */
//加集合元素
c.add("one");
c.add("two");
c.add("three");
//输出集合
System.out.println(c); //[one, two, three] 集合没有长度 //自己写的方法要重写toSring方法
/**
* int size()
* 获取当前集合的元素个数 不是长度,集合没有长度
* */
//显示个数,不是长度,集合没有长度 //c.size()
System.out.println(c.size()); //3
/**
* boolean isEmpty()
* 判断当前集合是否为一个空集
* */
//判断当前集合是否为一个空集 //boolean
boolean isEmpty = c.isEmpty();
System.out.println(isEmpty); //false 不是空集 空集不是空
/**
* void clear()
* 清空集合,删除集合中所有的元素
* */
//清空集合 //c.clear();
c.clear();
System.out.println(c.size()); //个数是0
isEmpty =c.isEmpty();
System.out.println(isEmpty); //true 是空集
list.getFirdt() //LinkedList()也能用
list.getLast()
list.removeFirst() //移除,返回被移除的数据 首位
list.removeLast() //移除,返回被移除的数据 末尾
【contains方法】判断
该方法会用于判断给定的元素是否被包含在集合中。若包含则返回true,否则返回false。
这里需要注意的是,集合在判断元素是否被包含在集合中是使用元素的equals的比较结果。
比较规则如下:
(o==null ? e==null : o.equals(e))
Collection<Cell> cells = new ArrayList<Cell>();
cells.add(new Cell(1, 2));
cells.add(new Cell(1, 3));
cells.add(new Cell(2, 2));
cells.add(new Cell(2, 3));
Cell cell = new Cell(1, 3);
// List集合contains方法和对象的equals方法相关
boolean flag = cells.contains(cell);
// 如果Cell不重写equals方法将为false
System.out.println(flag); // true
集合的批量操作方法
/**
* 集合的批量操作方法
* addAll(Collection c)
* 将给定集合中的所有元素添加到当前集合
* 执行完毕后,若当前集合元素发生了变化就返回true
* containsAll(Collection c)
* 判断当前集合是否包含给定集合中的所有元素
* */
Collection c1 =new ArrayList();
c1.add("java");
c1.add("c");
c1.add("c++");
System.out.println(c1); //[java, c, c++]
//放进去的顺序改变,只要集合元素不变,输出的顺序不会改变
Collection c2 =new HashSet(); //Set集合用的不多,就是HashSet()可能会用
c2.add("php");
c2.add("object");
c2.add("c#"); //c撒
c2.add("java");
System.out.println(c2); //[php, java, c#, object]
把c2中的所有元素加到c1中
c1.addAll(c2); //如果没有All,则输出[java, c, c++, [php, java, c#, object]]
System.out.println(c1);//[java, c, c++, php, java, c#, object]
Collection c3 =new LinkedList();
c3.add("java");
c3.add("php");
c3.add("c++");
判断c1集合是否包含c3集合中的所有元素
boolean contains =c1.containsAll(c3); //必须写All,不然就是false
System.out.println(contains); //true
【Iterator】迭代器遍历集合
Iterator用于遍历集合元素。获取Iterator可以使用Collection定义的iterator方法。
Iterator的next方法用于返回迭代的下一个元素,hasNext方法用于判断集合是否还有元素可以遍历。
在使用Iterator遍历集合时,不能通过集合的remove方法删除集合元素,否则会抛出异常。我们可以通过迭代器自身提供的remove()方法来删除通过next()迭代出的元素。
增强for循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器模式,所以增强for循环本质上是迭代器。
迭代器与for循环相比,不用每次都从头开始遍历,只用挨着循环一次
ArrayList<Integer> list =new ArrayList<Integer>();
list.add(666);
list.add(555);
list.add(null);
list.add(999);
Iterator<Integer> it =list.iterator();
while(it.hasNext()){
Integer s=it.next();
System.out.println(s); //666 555 null 999
}
获取元素 删除元素 //迭代器 die迭
Collection c=new ArrayList();
c.add("one");
c.add("#");
c.add("two");
c.add("#");
c.add("three");
c.add("#");
//import java.util.Iterator;
Iterator it =c.iterator(); //迭代器遍历集合
/**
* boolean hasNext()
* 该方法是判断集合中是否还有元素可以被取出
* */
while(it.hasNext()){
/**
* E next()
* 获取集合中当前元素
* 需要注意,要确定hasNext为true才能调用这个方法
* */
Object obj=it.next();
String str =(String)obj; //可以没有这一步,直接用System.out.print(obj+" ");
System.out.print(str+" "); //one # two # three #
//删除所有的“#”
if("#".equals(str)){ //只能在迭代器内用
/**
* 使用迭代器遍历集合的过程中,不能通过集合定义
* 的方法对元素数量进行修改,否则可能抛出异常
* */
//c.remove(str); //List.remove("four");//List.remove(2);
/**
* 迭代器的remove方法会将next()遍历出来的元素从集合中删除
* */
it.remove();
}
}
System.out.println(c);//[one, two, three]
新for循环获取数组
/**
* 新循环,增强循环,增强for循环,for each
* java5.1推出的新特性
* 用于遍历集合获取数组的
* */
String[] array = {"a","b","c","d","e"};
for (int i = 0; i < array.length; i++) {
String str =array[i];
System.out.println(str); //abcde
}
for(String str : array ){
System.out.println(str); //abcde
}
例子:
Collection c =new ArrayList();
c.add("one");
c.add("two");
c.add("three");
//方法一:比较复杂 //迭代器
Iterator it =c.iterator();
while (it.hasNext()){
Object o =it.next();
System.out.println(o); //one two three
}
//方法二:比较方便 //新for循环
/**
* 新循环是编译器认可的而非JVM
* 编译器会在编译程序的时候将新循环改为迭代器
* 模式,所以不能在循环过程中删除元素
* */
for(Object o:c){ //新for循环不能在循环过程中删除元素
System.out.println(o); //one two three
}
for(Iterator<Integer> it =c.iterator();it.hasNext();){
Integer inte=it.next();
}
【泛型】 //两边的泛型要一样
/**
* 泛型
* 对于Position类而言
* 创建实例时,x,y的实际类型为Object
* */
【泛型的继承】
List<? super Integer> lis1 =new LinkedList<Object>();
List<? extends Object> lis2 =new LinkedList<Integer>();
/**
* 由于我们使用了泛型约束了方法参数的类型,那么编译器会自动检查我们
* 实际传入的参数是否满足类型,不满组则编译不通过
泛型,对集合中存放的数据类型进行限制,不支持基本类型int,可用基本类型的包装类型Integer
* */
Position<Integer,Double> p= //泛型< >内要用引用类型,不能是基本数据类型
new Position<Integer, Double>(1,9.0);
int x1 =p.getX();
double y1=p.getY();
System.out.println(x1+","+y1);
/**
* 当泛型约束方法返回值后,那么实际返回是会自动强制类型转换
* */
//int x2 =p.getX();//(返回的是Integer,再自动拆箱成int)不推荐如果上面是null,会出现空指针异常
Integer x2=p.getX(); //推荐这种方式
/**
* 若没有指定泛型的具体类型,默认就是Object
* */
Position p2 =p; //没有< >默认就是Object
p2.setX("张三"); //从Object变成String
String xx =(String)p2.getX();
System.out.println("xx:"+xx); //xx:张三
/**
* 由于x是以p2的角度时已经改成了String类型的实例
* 在这里隐式转换为Integer的时候会出现类造型异常
* */
x2=p.getX();//String不可以强转为Integer
System.out.println(x2); //类造型异常
package day04;
import javax.security.auth.x500.X500Principal;
public class Position<X,Y> {
private X x;
private Y y;
public Position(X x, Y y) {
super();
this.x = x;
this.y = y;
}
public X getX() {
return x;
}
public void setX(X x) {
this.x = x;
}
public Y getY() {
return y;
}
public void setY(Y y) {
this.y = y;
}
}
泛型用来约束集合中的元素类型
/**
* 泛型在集合中的应用
* 泛型用来约束集合中的元素类型
* */
Collection<String> c =new ArrayList<String>();
c.add("one");
c.add("two");
c.add("three");
for(String str :c){
System.out.println(str);
}
/**
* 迭代器也支持泛型,泛型的类型应当与遍历的集合
* 所定义的泛型类型一致即可
* */
Iterator<String> it =c.iterator();
while(it.hasNext()){ //这样遍历出来后,就不用强转了
String str=it.next();
System.out.println(str);
}
方法泛型
Private static <E> Hoider<E> f(E e){ // <T> T f(T t)
Holder<E> h=new Holder<E>();
h.setV(e);
return;
}
【List集合】 //选推荐的第二个类
/**
* List集合 //选推荐的第二个类
* 可重复集
* 特点:有序集,可以通过下标操作元素
* 常用实现类ArrayList,LinkedList
* ArrayList内部由数组实现,利于查询,不利于增删
* LinkedList内部由链表实现,利于增删,不利于查询
* */
//List集合ArrayList,LinkedList
List<String> list=new ArrayList<String>();//List导入import java.util.List;
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list); //[one, two, three, four, five]
/**
* E get(int index)
* List集合的get方法用于获取指定下标对应的元素
* */
//通过下标获取元素
String els= list.get(2); //是下标
System.out.println(els); //three
/**
* 对于list,也可以使用类似遍历数组的方式
* 通过下标遍历每一个元素
* */
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i));//one two three four five
}
/**
* E set(int index,E e)
* 将给定的元素设置到给定的位置上,返回值为原位置上的元素,实质上就是替换操作
* */
//替换操作
String old= list.set(1, "2"); //下标不能超过集合元素个数
System.out.println(list);//[one, 2, three, four, five]
System.out.println("old:"+old); //old:two
//替换操作 //互相转换
//Collections.swap(i,j); //替换操作 //互相转换
/**
* List提供了一套方法
* void add(int index,E e)
* E remove(int index)
* */
List<String> list=new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);//[one, two, three, four, five]
/**
* void add(int index,E e)
* 将给定的元素插入到给定的位置上,原位置以及后续元素顺序向后移动
* */
//插入元素
list.add(2,"3"); //搜索.add(0
System.out.println(list);//[one, two, 3, three, four, five]
/**
* E remove(int index)
* 将给定位置的元素删除并返回
* */
//删除元素并返回
String old= list.remove(3); //list.remove(Integer.valueOf(3)); //如果集合内元素是int型,3就只能表示下标,不能表示元素,要删掉元素3,则必须要用包装Integer.valueOf(3)
System.out.println(list);//[one, two, 3, four, five]
System.out.println(old); //three
/**
* List提供了一个可以获取子集的方法
* */
//获取子集
List<Integer> list =new ArrayList<Integer>();
for(int i=0;i<10;i++){
list.add(i);
}
System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
/**
* List subList(int start,int end)
* 获取当前集合中指定范围的子集
* */
List<Integer> subList =list.subList(3, 8);
System.out.println(subList); //[3, 4, 5, 6, 7]
/**
* 将子集中每个元素扩大10倍
* */
//将子集中每个元素扩大10倍
for(int i=0;i<subList.size();i++){
subList.set(i, subList.get(i)*10);
}
System.out.println(subList);//[30, 40, 50, 60, 70]
//修改子集会影响原集合
System.out.println(list);//[0, 1, 2, 30, 40, 50, 60, 70, 8, 9]
subList.clear();
System.out.println(subList);//[]
System.out.println(list);//[0, 1, 2, 8, 9]
/**
* 集合转换为数组
* Collection提供了一个方法toString()可以将
* 当前集合转换为数组
* */
//集合转换为数组
Collection<String> c=new ArrayList<String>();
c.add("one");
c.add("two");
c.add("three");
c.add("four");
/**
* Object toArray()
* */
//Object[] array =c.toArray(); //不太常用
/**
* T[] toArray(T[] t)
* 我们传入的数组可以存放集合的所有元素的话,就使用我们给定的数组,存不下
* 就创建一个同类型的数组
* */
String[] array =c.toArray(new String[c.size()]);
//如果是10,则输出onetwothreefournullnullnullnullnullnull
//如果是2,则输出onetwothreefour
for(String str:array){
System.out.print(str);//one two three four
}
/**
* 数组转换为集合
* 需要注意的是,只能转换为List集,不能转换为Set集
* Arrays.asList()
* */
//数组转换为集合
String[] array ={"one","two","three","four"};
List<String> list =Arrays.asList(array);
System.out.println(list);//[one, two, three, four]
//如果集合是从数组转换过来的,则不能添加元素
//不能添加元素
//list.add("five");//异常java.lang.UnsupportedOperationException
//可以替换
list.set(0, "1"); //返回的是被替换出来的元素
System.out.println(list);//[1, two, three, four]
//替换了集合,数组也会跟着改变
System.out.println(Arrays.toString(array));//[1, two, three, four]
/**
* 若想添加新元素,做这样的操作,需要创建一个新集合
* */
//若想添加新元素,需要创建一个新集合
List<String> newList =new ArrayList<String>(list);//(list)只要是集合就可放进去
System.out.println(newList);//[1, two, three, four]
newList.add("five");
System.out.println(newList);//[1, two, three, four, five]
删除元素,移除集合元素
newList.remove("four");
System.out.println(newList); //[1, two, three, five]
/**
* 集合的排序,排序只针对List集
* */
Random random =new Random();
List<Integer> list =new ArrayList<Integer>();
for(int i=0;i<10;i++){
list.add(random.nextInt(100));
}
System.out.println(list);//[13, 60, 85, 13, 24, 41, 32, 73, 84, 51]
/**
* 对集合进行自然排序
* 从小到大
* 使用集合的工具类Collections的静态方法sort
* Collection和Collections的区别
* Collection是集合的接口,定义了集合应有的行为
* Collections是集合的工具类,提供了方便操作集合的方法
* */
//排序
Collections.sort(list);
System.out.println(list); //[13, 13, 24, 32, 41, 51, 60, 73, 84, 85]
//替换操作 //互相转换
//Collections.swap(i,j); //替换操作 //互相转换
【Comparable】排序
第一种方法:实现接口Comparable //不太常用 //用于ArrayList<Point>
package day05;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class SortCollectionDemo1 {
public static void main(String[] args) {
List<Point> list =new ArrayList<Point>(); //Point<>要重写toString方法
list.add(new Point(1, 2));
list.add(new Point(6,7));
list.add(new Point(3 , 4));
list.add(new Point(5, 5));
System.out.println(list); //[(1,2), (6,7), (3,4), (5,5)]
/**
* 要排序的集合必须保证其元素是可以比较大小的
* */
//要排序的集合必须保证其元素是可以比较大小的
Collections.sort(list); //实现接口,重载方法后可以排序
System.out.println(list);//[(1,2), (3,4), (5,5), (6,7)]
}
}
package day05;
//若当前类的实例间可以比较大小,当前类要实现接口Comparable,
//并重写比较方法。
public class Point implements Comparable<Point>{ //实现接口Comparable
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String toString(){
return "("+x+","+y+")";
}
/**
* 当我们实现了Comparable接口后,要求重写该方法
* 该方法的作用是定义Point两个对象间比较大小的逻辑
* 该方法的放回值为一个int型。放回值不关注具体取值是多少,只关注取值范围
* 若返回值>0:当前对象比参数对象大
* 若返回值=0:当前对象比参数对象相等
* 若返回值<0:当前对象比参数对象小
* */
//重写Comparable接口的compareTo(Point o)方法
public int compareTo(Point o) {
/**
* 判断标准,坐标点到原点的距离长的就大
* */
//判断标准,坐标点到原点的距离长的就大
int len=this.x*this.x+this.y*this.y;
int olen=o.x*o.x+o.y*o.y;
return len-olen;
}
}
第二种方法:比较器Comparator //更常用
package day05;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SortCollectionDemo2 {
public static void main(String[] args) {
List<String> list =new ArrayList<String>();
list.add("boss");
list.add("good");
list.add("No");
list.add("Fine");
System.out.println(list);//[boss, good, No, Fine]
Collections.sort(list);
System.out.println(list);//[Fine, No, boss, good]
list.add("我们");
list.add("你就是");
list.add("他很调");
list.add("明天见");
/**
* sort方法按照元素自身定义的比较规则,但是某些情况下,元素自身提供的比较规则
* 不能满足我们对于排序需求时,就应当使用重载的sort方法
* */
System.out.println(list);//[Fine, No, boss, good, 我们, 你就是, 他很调, 明天见]
/**
* static void sort(List list,Comparator com) 比Comparable接口更常用
* 重载的sort方法要求我们传入一个比较器,这是一个临时的比较规则
* sort可以按照比较器的比较规则对list集合中的元素进行比较大小,然后进行自然排序
* 因为使用自定义的比较器,所以该方法不要求list集合中的元素必须实现Comparable接口。
* */
//比较汉字,用长度
Comparator<String> com=new Comparator<String>(){ //匿名内部类
public int compare(String o1,String o2){
return o1.length()-o2.length();
}
};
Collections.sort(list,com);
System.out.println(list);//[No, 我们, 你就是, 他很调, 明天见, Fine, boss, good]
}
}
str0.compareToIgnoreCase(str1) //无视大小写比较字母
Collections.sort(list, new Comparator<Contacts>() { //汉字的比较,按字母 //汉字排序
@Override
public int compare(Contacts lhs, Contacts rhs) {
Comparator<Object> cmp0=Collator.getInstance(java.util.Locale.CHINA);
String str0=lhs.getName();
String str1=rhs.getName();
String[] strs={str0,str1};
Arrays.sort(strs,cmp0);
if(strs[0].equals(str1)) {
return 1;
}
return -1;
}
});
【队列】【Queue】 先进先出 【集合】【LinkedList】
JDK中提供了Queue接口来实现队列这个数据结构,同时使得LinkedList实现了该接口;
同时,JDK中还提供了Deque接口来实现栈这个数据结构,而 LinkedList也实现了该接口。
如果只在两端操作数据,选择LinkedList
只要会操作中间的数据,就用ArrayList
/**
* 队列
* 该数据结构与集合相似之处在于也是用于存放一组元素只能从队首获取
* 所以不能插入元素,也不能任意获取其中某个元素
* */
//队列queue //集合LinkedList
Queue<String> queue =new LinkedList<String>();
/**
* boolean offer(E e) //addLast
* 向队尾追加元素
* */
//向队尾追加元素
queue.offer("one");
queue.offer("two");
queue.offer("three");
queue.offer("four");
System.out.println(queue);//[one, two, three, four]
/**
* E poll()
* 从队首获取元素,出队操作
* 需要注意,调用后,队首元素就从队列中被移除了
* */
//引用队首元素,并删除poll();
String str =queue.poll();
System.out.println(str);//one
System.out.println(queue);//[two, three, four]
//引用队首元素,但不删除peek();
str =queue.peek();
System.out.println(str);//two
System.out.println(queue);//[two, three, four]
/**
* 遍历队列
* int size()
* 队列也有size方法,用于获取队列元素个数
* */
遍历队列
方法一:
for(int i=queue.size();i>0;i--){
System.out.println(queue.poll()); //two three four
}
方法二:
while(queue.size()>0){
System.out.println(queue.poll()); //two three four
}
【栈】【Deque】 先进后出 【集合】【LinkedList】
/**
* 栈
* 同样可以存储一组元素,栈必须遵循“先进后出”原则
* 栈用于解决一些列的操作可追溯。例如:后退功能
* 站内没东西了,还pop();会出异常。
* */
//栈Deque 先进后出
Deque<String> stack =new LinkedList<String>();
/**
* 双端队列,若只调用一端的进出队方法,就形成了栈的效果
* */
/**
* void push()
* 入栈操作
* */
//入栈操作
stack.push("one");
stack.push("two");
stack.push("three");
stack.push("four");
stack.push("five");
System.out.println(stack);//[five, four, three, two, one]
/**
* E pop() //removeFist
* 出栈之后,获取栈顶元素,并且该元素会从栈中被删除
* */
//出栈之后,该元素会从栈中被删除
String str =stack.pop();
System.out.println(str); //five
System.out.println(stack); //[four, three, two, one]
//同样的peek方法也可以引用栈首元素,而不做出战操作
String str0 =stack.peek();
System.out.println(str0); //four
System.out.println(stack); //[four, three, two, one]
//遍历栈也是一次性的
while(stack.size()>0){
System.out.print(stack.pop());//four three two one
}
System.out.println(stack); //[]
【HashSet】
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;
特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
add(数据)
remove(数据)
size()
iterator()
contains(数据)
clear()
不支持下标index访问
【Map接口】-又称查找表 //HashMap //TreeSet //没继承Collection
Map集合的用处
Map接口定义的集合又称查找表,用于存储所谓“Key-Value”映射对。Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。
/**
* map 以key-value对的形式存放数据
* 其中key在Map中是不允许重复的
* 常用的实现类: HashMap
* java.util.*
* Map的key与value的类型是分开指定的
* */
Map<String, Integer>map =new HashMap<String, Integer>();
/**
* V put(K key,V v)
* 将给定的key与value存放入Map中
* 由于Map中不允许存放重复的key,所以,若给定的key已经在Map中存在,
* 则是替换value操作,那么put方法的返回值就是被替换的元素,否则
* 返回null
* */
//将给定的key与value存放入Map中
map.put("语文", 98); //Integer a=map.put("语文", 98);用Integer 不用int,容易出现异常
map.put("数学", 98);
map.put("英语", 98);
map.put("物理", 98);
map.put("化学", 98);
System.out.println(map);//也重写了toString{物理=98, 语文=98, 英语=98, 数学=98, 化学=98}
//替换
//重复输入的元素,被替换出来的是之前的元素的值
Integer re =map.put("化学", 100);
System.out.println(map); //{物理=98, 语文=98, 英语=98, 数学=98, 化学=100}
System.out.println(re); //被替换出来的,之前的值98
//新输入的元素,被替换出来的是null
Integer ac =map.put("生物", 80);
System.out.println(map);//{物理=98, 语文=98, 英语=98, 数学=98, 化学=100, 生物=80}
System.out.println(ac); //null
/**
* V get(K k)
* 根据给定的key获取对应的value
* 若给定的key在当前Map中不存在,则返回null
* */
//通过key获取value值
Integer number =map.get("语文");
System.out.println("语文:"+number);//语文:98
/**
* boolean containsKey(K k)
* 判断给定的key是否在Map中存在
* 判断依据也是根据给定的key与Map中所有的key是否具有
* equals比较为true
* */
//判断是否存在某个元素
boolean contains =map.containsKey("化学");
System.out.println("包含化学:"+contains);//包含化学:true
输出无序
HashMap<Integer,String> map=new HashMap<Integer, String>();
map.put(111, "111");
map.put(222, "222");
map.put(555, "555");
map.put(777, "777");
map.put(333, "333");
map.put(444, null);
map.put(null, "111"); //key能为null //改正过 //但只能有一个key为null,有两个也只能显示一个
map.put(666, "666");
map.put(111, "112");
System.out.println(map); //{null=111, 222=222, 444=null, 666=666, 111=112, 333=333, 555=555, 777=777}
System.out.println(map.size()); //8
System.out.println(map.get(333)); //333
System.out.println(map.remove(444)); //返回值为null
System.out.println(map.containsKey(555)); //true
System.out.println(map.containsValue("999")); //false
System.out.println(map);//{null=111, 222=222, 666=666, 111=112, 333=333, 555=555, 777=777}
【hashcode】 //无序 //但只要输入的数据一样,其顺序不变 //哈希值 //散列码
/**
* 重写一个类的equals方法时,应当连同重写hashcode方法
* 因为,若当前类的实例在Map中作为key使用时,这两个方法对于HashMap
* 的性能产生着直接的影响
* 要求:
* 1.若两个对象equals比较为true,那么hashcode方法返回的数字必须相同
* 反之没有要求,但是应当尽量保证两个对象hashcode不同equals方法也应为
* false。否则对HashMap性能产生直接影响
* 2.hashcode方法返回的数字应该是一个稳定的值,意思是若当前对象的属性
* 没有发生改变,hashcode方法返回的数字不应该变化
* */
hashCode方法的意义
以java.lang.Object来理解,JVM每实例化一个Object,它都会将这个Object放入到一个Hash哈希表中去,这样的话,
下次做Object的比较或者取这个对象的时候,它会根据对象的hashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程如下:
1) new Object(),JVM根据这个对象的hashCode值,放入到对应的Hash表对应的Key上,如果不同的对象产生了相同的hash值,
也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashCode的对象放到这个单链表上去,串在一起,就是Hash桶。
2) 比较两个对象的时候,首先根据他们的hashCode去hash表中找它的对象,当两个对象的hashCode相同,也就是说这两个对象
放在Hash表中的同一个key上,则他们一定在这个key上的链表上。那么此时就只能根据Object的equals方法来比较这个对象是否相等。当两个对象的hashCode不同时,则这两个对象一定不能相等。
1.通过key.hashCode()得出哈希值
2.用哈希值计算出下标index
3.新建Entry对象 //包括key和value
4.将Entry对象放入index位置
4.1. index是空位置,会直接放入
4.2. index位置有entry对象
4.2.1 依次比较equals()比较键是否相等
4.2.1.1 找到相等的,覆盖掉之前的
4.2.1.2 没有找到相等的,挂在一起,形成链表
只有对象作为哈希表的键时,才有用
将对象的内存地址值,处理成int,
如果对象作为键,放入哈希表,必须重写hashCode()方法
可以使用对象属性,来计算产生hashCode、
容量桶使用超过75%,就加大容量桶个数,使空容量桶变多。
通过加大容量桶的个数,减少哈希值相等的情况,使得每一个容量桶内元素的个数减少 ,
class Cell{
private int row;
private int col;
public Cell(int row, int col) {
super();
this.row = row;
this.col = col;
}
@Override
public int hashCode() { //可一键生成
final int prime = 31;
int result = 1;
result = prime * result + col;
result = prime * result + row;
return result;
}
@Override
public boolean equals(Object obj) { //可一键生成
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Cell other = (Cell) obj;
if (col != other.col)
return false;
if (row != other.row)
return false;
return true;
}
}
【装载因子及HashMap优化】
在散列表中有一下名词需要了解:
Capacity:容量, hash表里bucket(桶)容量桶的数量, 也就是散列数组大小.
Initial capacity:初始容量, 创建hash表的时 初始bucket的数量, 默认构建容量是16. 也可以使用特定容量.
Size : 大小, 当前散列表中存储数据的数量.
Load factor:加载因子, 默认值0.75(就是75%), 向散列表增加数据时如果 size/capacity 的值大于Load factor则发生扩容并且重新散列(rehash).
那么当加载因子较小时候散列查找性能会提高, 同时也浪费了散列桶空间容量. 0.75是性能和空间相对平衡结果. 在创建散列表时候指定合理容量, 从而可以减少rehash提高性能。
【遍历Map有三种方式】
/**
* 遍历Map有三种方式
* 遍历所有的key
* 遍历所有的key-value对
* 遍历所有的value(不常用)
* */
Map<String ,Integer> map=new HashMap<String, Integer>();
//new LinkedHashMap {语文=98, 数学=99, 英语=98, 物理=98, 化学=98} 有序的
map.put("语文",98);
map.put("数学",99);
map.put("英语",98);
map.put("物理",98);
map.put("化学",98);
System.out.println(map);//{物理=98, 语文=98, 英语=98, 数学=99, 化学=98} 无序的
/**
* 遍历所有的key
* Set<K> keySet()
* 该方法会将当前Map中的所有key存入一个Set集合
* 后将其返回,所以遍历该集合就相当于遍历了所有的key
* */
//遍历所有的key //遍历key //新for循环
Set<String> keyset =map.keySet();
for(String key:keyset){
System.out.print("key:"+key); //key:物理key:语文key:英语key:数学key:化学
}
//另一个例子中key为Integer,value为String。
//for(Iterator<Integer> it=keyset.iterator();it.hasNext();){
// Integer k=it.next(); String v=map.get(k);System.out.println(k+"="+v);
//}
/**
* 遍历每一组键值对
* Set<Entry> entrySet()
* Map有一个内部类Entry,其定义了两个属性,分别是
* Key与Value,那么每一个Entry实例就可以表示Map
* 中的一组键值对
* 所以entrySet方法就是将Map中的每一组键值对(每一个Entry)
* 存入Set集合然后返回
* Entry的泛型应当与Map的泛型一致
* */
//遍历每一组键值对entry
Set<Entry<String,Integer>> entrySet =map.entrySet();
for(Entry<String , Integer> entry: entrySet){
String key =entry.getKey();
Integer value=entry.getValue();
System.out.print(key+":"+value);//key:物理key:语文key:英语key:数学key:化学物理:98语文:98英语:98数学:99化学:98
}
//另一个例子中key为Integer,value为String。
//for(Iterator<Entry<Integer,String>> it=entrySet.iterator();it.hasNext();){
// Entry<String , Integer> e=it.next(); Integer k=e.getKey();String v=e.getValue():System.out.println(k+"="+v);
//}
/**
* 遍历所有的value
* Collection<V> values()
* 将Map中所有的value存入一个集合然后返回
* 这个集合不是Set,因为Map可以存放重复的value
* */
//遍历所有的value //不常用 //不能用Set,因为Set内不可重复,而Map的Value值可重复,只有key不可重复
Collection<Integer> values=map.values();
for(Integer value:values){
System.out.println(value); //98 98 98 99 98
}
//另一个例子中key为Integer,value为String。
//for(Iterator<String> it=value.iterator();it.hasNext();){
// String v=it.next(); System.out.println(v);
//}
【TreeMap】
树形,左小,中间中等,右边大,先从从简开始,一层一层往下跑,只用跑几层。
Key键值:
1.不重复
2.有序的
3.不容许null值(空值)
创建对象
1. TreeMap map =new TreeMap();
2. //输出从小到大
HashMap<Integer,String> map=new HashMap<Integer, String>();
map.put(111, "111");
map.put(222, "222");
map.put(555, "555");
map.put(777, "777");
map.put(333, "333");
map.put(444, "null");
//map.put(null, "111"); //key不能为null
map.put(666, "666");
map.put(111, "112");
System.out.println(map); //{111=112, 222=222, 333=333, 444=null, 555=555, 666=666, 777=777}
System.out.println(map.size()); //7
System.out.println(map.get(333)); //333
System.out.println(map.remove(444)); //返回值为null
System.out.println(map.containsKey(555)); //true
System.out.println(map.containsValue("999")); //false
System.out.println(map);//{111=112, 222=222, 333=333, 555=555, 666=666, 777=777}
//如两种方法都有,则使用比较器的代码
第一种方法: //用于TreeMap //使用实现implements Comparable接口
package day04;
import java.util.TreeMap;
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
Point p1 =new Point(1,3);
Point p2 =new Point(2,5);
TreeMap<Point, String> map =new TreeMap<Point, String>();
map.put(p1, "2.9亿");
map.put(p2, "3亿");
System.out.println(map); //{(x=1, y=3)=2.9亿, (x=2, y=5)=3亿}
}
}
package day04;
public class Point implements Comparable<Point>{
private int x;
private int y;
public Point() {
super();
}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "(x=" + x + ", y=" + y + ")";
}
@Override
public int compareTo(Point o) {
return x-o.x;
}
}
第二种方法: //用于TreeMap //使用自制比较器Comparator,没用实现
package day04;
import java.util.Comparator;
import java.util.TreeMap;
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
Point p1 =new Point(1,3);
Point p2 =new Point(2,5);
Comparator<Point> comp =new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
return o1.getY()-o2.getY();
}
};
TreeMap<Point, String> map =new TreeMap<Point, String>(comp);
map.put(p1, "2.9亿");
map.put(p2, "3亿");
System.out.println(map); //{(x=1, y=3)=2.9亿, (x=2, y=5)=3亿}
}
}
package day04;
public class Point{
private int x;
private int y;
public Point() {
super();
}
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "(x=" + x + ", y=" + y + ")";
}
}
【枚举】【enum】
一组固定选项
可以代替数字代码常量
枚举本质就是类
enum关键字,代替class关键字
固定的枚举选项,本质是枚举类的实例
public enum Type{
COLD,HEAT,NUCLEAR
}
public class Type{
public static final Type COLD=new Type();
public static final Type HEAT =new Type();
public static final Type NUCLEAR=new Type();
}
void f(Type t){
}
f(Type.COLD);
f(Type.HEAT);
Type t =weapon.getType();
switch(t){ //变形金刚
case COLD: //不用Type.COLD //枚举的特性
case HEAT:
}
【异常】
封装错误信息的对象
对象类型名称
错误提示
出错行号
异常继承结构
Throwable
|-Error 系统级错误 //比如超出内存memory
|-Exception 可以编写代码修复的错误
|-其他 //需要手动设置异常抛出管道 //如果不设置,就要捕获这种异常
|-RuntimeException //和其子类型存在默认的异常抛出管道
|-NullPointException
|-ArrayIndexOutOfBoundsException
|-NumberFormatException //数字格式异常
|-ArithmeticException //计算异常
异常捕获
package day05;
import java.util.Scanner;
public class Test1 {
public static void main(String[] args) {
while(true){ //异常捕获
try{
test2();
break;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("请输入两个数字,不是一个");
}catch(NumberFormatException e){
System.out.println("请输入整数");
}catch(Exception e){ //父类错误要放在后面,不然子类错误就没用了
System.out.println("不懂你输入的是什么东西!");
}finally{
System.out.println("绝对会执行的");
}
}
}
private static void test2(){
System.out.println("输入逗号隔开的两个整数");
String s=new Scanner(System.in).nextLine();
String[] arr =s.split(",");
int a =Integer.parseInt(arr[0]);
int b=Integer.parseInt(arr[1]);
int c =a/b;
System.out.println(a+"+"+b+"="+c);
System.out.println(180.0/0); //Infinity无穷大
}
}
设置异常抛出管道
package day05;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Test2 {
public static void main(String[] args) {
try{
test1();
}catch(ParseException e){
System.out.println("亲,你输入的不是日期!");
}
}
private static void test1() throws ParseException{ //throws**设置异常抛出管道
System.out.println("输入日期(yyyy-MM-dd),"+"显示该日期距离"+"1970-1-1 0点多少毫秒");
String s =new Scanner(System.in).nextLine();
SimpleDateFormat f=new SimpleDateFormat("yyyy-MM-dd");
Date d=f.parse(s);
System.out.println(d.getTime());
}
}
记录异常
try{
test1();
}catch(Exception e){
e.printStackTrace(); //java.text.ParseException: Unparseable date: "15415hy"
System.out.println(e.getMessage());//Unparseable date: "15415hy"
}
【finally】 //最后会执行
try{
test2();
break;
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("请输入两个数字,不是一个");
}catch(NumberFormatException e){
System.out.println("请输入整数");
}catch(Exception e){ //父类错误要放在后面,不然子类错误就没用了
System.out.println("不懂你输入的是什么东西!");
}finally{ //最后会执行
System.out.println("绝对会执行的");
}
【File】表示一个文件或目录
//为了避免在不同系统上运行时的异常,所以目录用相对目录,不用绝对目录
/**
* java.io.File
* 该类用于表示一个文件或目录
* 使用该类可以获取表示的文件或目录的属性信息
* 但是不能访问文件的内容
* 使用该类还可以操作文件或目录(新建,删除等)
("d:\\a.txt"); (目录,文件名)
File f1 =new File("d:\\good.txt"); //存在的文件
File f2= new File("D:\\workspace_1503","study.txt"); //存在的文件
File f4= new File("D:\\workspace_1503"); //存在的目录
File f3 =new File("d:\\goodday.txt"); //不存在的文件
System.out.println("可读:"+f1.canRead()); //可读:true
System.out.println("可写:"+f1.canWrite()); //可写:true
System.out.println("可执行:"+f1.canExecute()); //可执行:true
System.out.println("隐藏:"+f1.isHidden()); //隐藏:false
System.out.println("存在:"+f1.exists()); //存在:true
System.out.println("完整路径:"+f1.getAbsolutePath()); //完整路径:d:\good.txt
System.out.println("文件名:"+f1.getName()); //文件名:good.txt
System.out.println("父目录:"+f1.getParent()); //父目录:d:\
System.out.println("最后修改时间(毫秒):"+f1.lastModified()); //最后修改时间(毫秒):1429258060390
System.out.println("字节量:"+f1.length()); //字节量:61
System.out.println("是目录:"+f1.isDirectory()); //是目录:false
System.out.println("字文件:"+f1.isFile()); //字文件:true
System.out.println("总空间:"+f1.getTotalSpace()); //总空间:143670931456
System.out.println("可用空间:"+f1.getFreeSpace()); //可用空间:133532409856
createNewFile(); //创建文件
dir.mkdirs(); //创建多重目录
dir.mkdir(); //创建目录
* */
/**
* 创建一个File用来表示项目根目录下的test.txt文件
* ("./test.txt");表示当前项目的目录 //只表示当前目录时./可以省略
* File.separator表示/或者\
* */
File file =new File("."+File.separator+"test.txt"); //不会创建新的
/**
* 判断表示的文件是否真实存在于硬盘上
* boolean exists()
* */
//判断表示的文件是否真实存在于硬盘上
if(file.exists()){
System.out.println("文件存在");//文件存在
}else{
System.out.println("文件不存在");
}
/**
* long length()
* 查看当前文件占用的字节量
* */
//查看当前文件占用的字节量
long length =file.length();
System.out.println("占用"+length+"字节"); //占用18字节
/**
* boolean isFile()
* 判断当前File对象表示的是不是一个文件
* 是则返回true
* */
//判断当前File对象表示的是不是一个文件
if(file.isFile()){
System.out.println("是文件");//是文件
}else{
System.out.println("不是文件");
}
/**
* boolean isDirectory()
* 判断当前File对象表示的是否为一个目录
* */
//判断当前File对象表示的是否为一个目录
if(file.isDirectory()){
System.out.println("是目录");
}else{
System.out.println("不是目录");//不是目录
}
/**
* 以下三个方法返回boolean值
* 分别表示:
* 可运行,可读,可写
* */
//可运行,可读,可写
// file.canExecute()
// file.canRead()
// file.canWrite()
/**
* 文件的最后写该时间
* long表示1970年元旦到这一刻的毫秒值
* */
//文件的最后写该时间
long last =file.lastModified();
Date date=new Date(last);
System.out.println(date);//2015-04-09
SimpleDateFormat sdf =new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String str =sdf.format(date);
System.out.println(str); //2015年04月09日 16:37:18
/**
* String getName()
* 获取当前File对象表示的文件或目录名
* */
//获取当前File对象表示的文件或目录名
String name=file.getName();
System.out.println(name);//test.txt
/**
* 在当前项目根目录下创建文件demo.txt
* */
//在当前项目根目录下创建文件
File file =new File("demo.txt");
//若不存在才创建
if(!file.exists()){
file.createNewFile(); //创建文件
System.out.println("创建完毕");//创建完毕
}
/**
* 删除一个文件
* 删除项目根目录下的demo.txt文件
* */
//删除项目根目录下的demo.txt文件
File file =new File("demo.txt");
if(file.exists()){
file.delete();
System.out.println("删除完毕");//删除完毕
}
/**
* 在当前项目根目录下创建子目录demo
* */
//创建目录 //创建文件夹
File dir =new File("demo");
if(!dir.exists()){
dir.mkdir();
System.out.println("创建完毕");
}
//删除目录,删除文件
//这个文件夹必须是空的,内面不能有文件或文件夹
File dir =new File("demo");
if(dir.exists()){
dir.delete();
System.out.println("删除完毕"); //删除完毕
}
/**
* 在当前项目根目录下创建目录:a/b/c/d/e/f
* */
//创建目录:a/b/c/d/e/f //创建文件夹
File dir =new File(
"."+File.separator+"a"+
File.separator+"b"+
File.separator+"c"+
File.separator+"d"+
File.separator+"e");
if(!dir.exists()){
dir.mkdirs(); //创建目录
System.out.println("创建完毕"); //创建完毕
}
/**
* 查看一个目录下的所有子项
* */
//查看一个目录下的所有子项
File dir =new File(".");
/**
* File[] listFiles() //dir.list();
* 将当前目录下的每一个子项用一个File对象去描述然后将他们存入一个数组返回
* */
File[] subs= dir.listFiles();
for(File sub:subs){
if(sub.isFile()){
System.out.println("是文件:"); //是文件: //是文件:
}
if(sub.isDirectory()){
System.out.println("目录:"); //目录: //目录: //目录:
}
System.out.println(sub.getName()); //bin //src //.settings //.project //.classpath
}
//目录:
//bin
//目录:
//src
//目录:
//.settings
//是文件:
//.project
//是文件:
//.classpath
遍历一个目录内的所有文件 //遍历文件名
package day18;
import java.io.File;
public class Test1 {
public static void main(String[] args) {
File dir =new File("D:\\1503下载\\java_code\\day01\\day0101_HelloWorld");
String[] names =dir.list(); //String[]
File[] files =dir.listFiles(); //File[]
for(String s:names){
System.out.print(s+" "); //.classpath .project .settings bin src //目录文件
}
System.out.println();
for(File f:files){
String n =f.getName();
long len =f.length();
System.out.print(n+" ");
if(f.isFile()){
System.out.println("------"+len);
}else{
System.out.println("------"+len);
}
}
}
}
//.classpath ------301
//.project ------394
//.settings ------0
//bin ------0
//src ------0
改文件的名字
File a =new File("d:\\f1");
File b =new File("d:\\f11");
if(a.exists()){
boolean bol =a.renameTo(b);
System.out.println("改名成功:"+bol);
}else{
boolean bol=b.renameTo(a);
System.out.println("改名成功:"+bol);
}
创建临时文件 //不确定
File.creatTempFile("d:\\","a.txt")
/**
* 使用文件过滤器FileFilter来获取一个目录下
* 满足条件的部分子项
* */
//过滤器FileFilter
//使用文件过滤器FileFilter来获取一个目录下满足条件的部分子项
FileFilter filter =new FileFilter() {
/**
* 实现FileFilter接口后必须重写accept方法
* 该方法用于定义过滤条件,若参数file满足过滤条件返回值久违true即可
* */
@Override
public boolean accept(File file) {
System.out.println("正在过滤:"+file.getName());//正在过滤:bin 正在过滤:src 正在过滤:.settings 正在过滤:.project 正在过滤:.classpath
return file.isFile();
}
};
File dir =new File(".");
//获取当前目录下满足过滤器要求的所有子项
File[] subs =dir.listFiles(filter);
for(File sub:subs){
System.out.println(sub.getName()); //.project //.classpath
}
//删掉当前目录下文件后缀为".jar"的文件,但不能删掉子文件中的文件
FileFilter filter =new FileFilter() { //过滤器FileFilter
public boolean accept(File file) {
if(file.isFile()){
if(file.getName().endsWith(".jar")){
return true;
}
}
return false;
}
};
File dir =new File(".");
File[] subs =dir.listFiles(filter);
for(File sub:subs){
System.out.println(sub.getName());
}
【递归删除】 //不能用循环就用递归
package day06;
import java.io.File;
public class FileDemo3 {
public static void main(String[] args) {
/**
* 删除给定的File对象
* 该对象可能表示文件也可能表示目录,总之要删除
* */
/**
* 将给定的File对象表示的文件或目录删除
* */
//递归删除 一个目录(文件夹)内所有目录文件或文件
File dirs =new File("a");
delete(dirs);
}
public static void delete(File file){ //递归删除,在方法内部调方法
if(file.isDirectory()){ //如果是空目录也会走这一步
//先将所有子项删除
File[] subs =file.listFiles();
for(File sub:subs){ //如果是空文件夹,就不会走下面这步进入循环,
delete(sub);
}
}
file.delete();
}
}
package day06; //1+2+3+.......+100
public class HomeWork1 {
int b = 0;
int i=1;
public static void main(String[] args) {
HomeWork1 a=new HomeWork1();
a.add();
System.out.println(a.b); //5050
}
public void add(){ //还可以用 if(n==1){return 1;} return n+add(n-1);
if(i<=100){
b =b+i;
if(i==100){
System.out.print(i+"=");
}else{
System.out.print(i+"+");
}
if(i%10==0){
System.out.print(‘\n‘);
}
i++;
add();
}
}
}
【读写文件数据】 //下载时,开几个线程分别从不同的字节开始下载 //断点续传
/**
* java.io.RandomAccessFile
* 该类用于读写文件数据
* */
/**
RandomAccessFile的两种创建模式
读写模式与只读模式
读写模式:可以读取文件数据,也可以向文件中写入数据
只读模式:只能读取文件数据
* RandomAccessFile的读写操作是基于指针的,总是在
* 指针当前指向的位置进行读写操作的
* */
/**
* 创建一个用于读写项目根目录下的test.dat文件的RandomAccessFile
* 两个常用的构造方法
* RandomAccessFile(String path,String mode)
* RandomAccessFile(File file,String mode)
* */
RandomAccessFile类的read方法和write方法使用int类型存储byte数据的方式和原因:
1)RandomAccessFile提供了一个可以从文件中读取字节的方法:
int read()
该方法会从文件中读取一个byte(8位) 填充到int的低八位, 高24位为0, 返回值范围正数: 0~255,
如果返回-1表示读取到了文件末尾! 每次读取后自动移动文件指针, 准备下次读取。
2)RandomAccessFile提供了一个可以向文件中写出字节的方法:
void write(int d)
该方法会根据当前指针所在位置处写入一个字节,是将参数int的”低8位”写出。
3)使用int类型存储byte数据,这是因为,RandomAccessFile类的read方法,能读到的数据有257个数值,
其中,0到255表示数据,-1表示读取到了文件末尾。而write方法与read方法是一对方法,因此write方法也采用了int类型。
新建
//方法一
// File file =new File("test.dat");
// RandomAccessFile raf1 =new RandomAccessFile(file, "rw");
//方法二
RandomAccessFile raf=new RandomAccessFile("test.dat","rw"); //创建文件
/**
* void write(int d)
* int四个字节 最大值为01111111 11111111 11111111 11111111
* 首位是符号位
* 向文件中写入一个字节,写出的是给定的int值2进制中的“低8位”
* 00000000 00000000 00000000 00000001 //是1
* 11111111 11111111 11111111 11111111 //负1,加1进位为0
* 永远是最后8个0
* */
//写入一个值 //最大255
raf.write(255); //最大255。 //256时,00000001 00000000只能读取到0
//raf.write(50);
raf.close();
//读取文件
RandomAccessFile raf2=new RandomAccessFile("test.dat","r");
/**
* int read()
* 从文件中读取一个字节,并以int形式返回,需要注意
* 该int值只有“低八位”有值
* 若读取到了文件末尾,负的最大值是-1,则返回-1
* EOF(end of file)
* */
int n =raf2.read();
//int c=raf2.read();
System.out.println(n); //255
//System.out.println(c) //50
raf2.close();
/**
* 1.创建RandomAccessFile读取源文件
* 2.创建RandomAccessFile用于写道目标文件
* 3.循环从源文件读取读取一个字节写入到目标文件,直到源文件所有内容都读取完毕
* 4.关闭RandomAccessFile
* */
//复制文件 //循环读取一个字节
RandomAccessFile src =new RandomAccessFile("test.txt", "r");
RandomAccessFile des =new RandomAccessFile("test_copy.txt", "rw");
long start =System.currentTimeMillis();
int d =-1;
while((d=src.read())!=-1){ //注意括号
des.write(d);
}
long end =System.currentTimeMillis();
System.out.println("文件复制完毕!");
System.out.println("耗时:"+(end-start)+"ms");
src.close();
des.close();
//批量写入 //写入字符串
RandomAccessFile raf =new RandomAccessFile("test.txt", "rw");
/**
* void write(byte[] d)
* 将给定的字节数组中的所有字节一次性写出
* */
String str ="摩擦摩擦在这光滑的地面上摩擦"; //复制在最上面
*将当前字符串按照系统默认字符集转换为对应的字节
byte[] date =str.getBytes(); //搜索Stringbyte //("GBK");
raf.write(date); //写入:摩擦摩擦在这光滑的地面上摩擦 //des.write(buf,0,len);下面有用
raf.close();
另一个例子:(
String s=“ABC中国”;
byte[] gbk =s.getBytes("GBK");//将字符串s中的字符按照“GBK”编码规则进行处理,
System.out.println(gbk.length); //7
)
//读取给定的字节量 //读文件和写文件要新建new两个对象,不能一个对象又读又写,除非用raf.seek(0);把指针返回到0位置才能用一个对象写之后再读
RandomAccessFile raf2 =new RandomAccessFile("test.txt", "r");
/**
* int read(byte[] d)
* 一次性尝试读取给定的字节数组的length个字节,并存入到给定的字节数组中
* 返回值为实际读取到的字节量。若返回值为-1,说明读取到文件末尾的。
* */
byte[] date2 =new byte[200];
int n =raf2.read(date2); //raf.read(buf,3,4); //读取buf内从下标3开始的4个字节, 不是区间的含头不含尾
System.out.println("实际读取到的字节量:"+n);//实际读取到的字节量:81
//System.out.println("实际读取到的字节量:"+n+Arrays.toString(date2));
//输出:实际读取到的字节量:28[-60, -90, -78, -63, -60, -90, -78, -63, -44, -38, -43, -30, -71, -30, -69, -84, -75, -60, -75, -40, -61, -26, -55, -49, -60, -90, -78, -63, 0, 0, 0, 0, 0,
/**
* 将字节转换为对应的字符串
* 可以使用String的构造方法
* String(byte[] d)
* 该构造方法会将给定的字节数组中的所有字节按照
* 当前系统默认的字符集转换为对应的字符串
* String(byte[] d,int offset,int len)
* 将当前字节数组从offset处开始的连续len个字节转换为对应的字符串
* */
*将字节数组中的所有字节转换为对应的字符串
* String str3=new String(date2,0,n); //只传一次 //(gbk,"GBK")
System.out.println(str3); //摩擦摩擦在这光滑的地面上摩擦
raf2.close();
循环读取多个字节:
byte[] date2 =new byte[4];
int n;
String cc = "";
while((n =raf2.read(date2))!=-1){
String str3=new String(date2,0,n);
cc+=str3;
}
System.out.println(cc);
编码
String s="ABC中国";
byte[] gbk =s.getBytes("GBK");//将字符串s中的字符按照“GBK”编码规则进行处理,
byte[] utf8 =s.getBytes("UTF-8"); //编码
System.out.println(gbk.length); //7
System.out.println(utf8.length); //9
String ss=new String(gbk,"GBK"); //解码
System.out.println(ss); //ABC中国
String s2= new String(utf8,"UTF-8"); //解码
System.out.println(s2); //ABC中国
String s3=new String(utf8,"GBK"); //解码成乱码
System.out.println(s3); //ABC涓浗
复制
若想要提高读写效率,需要提高读写的数据量,从而降低读写次数
RandomAccessFile src =new RandomAccessFile("test.txt", "r");
RandomAccessFile des= new RandomAccessFile("test_copy.txt", "rw");
byte[] buf =new byte[1024*10]; //10k 缓存 //常用8192 8k
//记录每次实际读取到的字节量
int len=-1;
long start =System.currentTimeMillis();
* while((len=src.read(buf))!=-1){ //传到传完为止
/**
* void write(byte[] d,int offset,int len)
*
* */
des.write(buf,0,len);
}
long end =System.currentTimeMillis();
System.out.println("复制完毕!");//复制完毕!
System.out.println("耗时:"+(end-start)+"ms"); //耗时:0ms
src.close();
des.close();
RandomAccessFile raf =new RandomAccessFile("demo.dat", "rw");
/**
* long getFilePointer()
* 该方法用于获取RAF当前指针位置
* */
【获取RAF当前指针位置】
System.out.println("point:"+raf.getFilePointer());//point:0
int max =Integer.MAX_VALUE;
//01111111 11111111 11111111 11111111
//raf.write(max>>>24); //向右移24位
raf.writeInt(max); //系统自己移四次,把最大值写出去
//写入四个字节
【writeInt】 //writeDouble(double d) // writeUTF(String s) abc 输出00 03 61 62 63 两个字节表示长度,剩下的的表示字符串//十六进制61是97
System.out.println("point:"+raf.getFilePointer()); //point:4
raf.writeLong(123L);
System.out.println("point:"+raf.getFilePointer()); //point:12
raf.writeDouble(123.123);
System.out.println("point:"+raf.getFilePointer()); //point:20
/**
* void seek(long pos)
* 将指针移动到指定位置
* */
//将指针移动到指定位置
raf.seek(0);
/**
* int readInt() //int有四个字节
* 连续读取4个字节,将对应的int值返回
* 若读取到文件末尾,-1,该方法会抛出异常
* 一开是就在末尾,就是-1,就会报错,所以要将将指针移动到指定位置0
* */
【readInt】 //readDouble //readUTF() 先读取2个字节来确定字符串的字节长度,再读取这些字节,转换成字符串
//连续读取4个字节 //因为会读取整数,可能是-1,所以不能用-1表示结束,用EOFException异常表示结束
int a=raf.readInt();
System.out.println(a);//2147483647
long l=raf.readLong();
System.out.println("long:"+l);//long:123
double d=raf.readDouble();
System.out.println("double:"+d); //double:123.123
raf.close();
RandomAccessFile raf =new RandomAccessFile("d:\\f4", "rw");
raf.write(97);
raf.write(98);
raf.writeInt(97);
raf.writeInt(98);
raf.writeUTF("abc中文");
raf.writeDouble(3.14);
raf.seek(0);
System.out.println(raf.read()); //97
System.out.println(raf.read()); //98
System.out.println(raf.readInt()); //97
System.out.println(raf.readInt()); //98
System.out.println(raf.readUTF()); //"abc中文"
System.out.println(raf.readDouble()); //3.14
raf.close();
【移位运算符】
计算机中数据管理单位是8位byte,文件IO都是8位单元组成
<< //左移 //数据的链接 //将数据byte合并为我们需要的数据,称为“反序列化”
11010011 10100110//向左移,右边加个0
>> //算术右移 //负数右移依然是负数
11010011 11101001//向右移,
>>> //逻辑右移 //负数右移变成正数 //将int long等数据进行拆分 //将数据拆分为byte数据才能写出到文件,称为“序列化”
11010011 01101001 //向右移,左边加个0
序列化和反序列化可以由API完成
将String拆分为byte数据才能写出到文件,称为“编码”
编码方式有:GBK GB2312 UTF-8 UTF-16BE
编码和解码的规则必须一致,否则乱码
int c=8;
Log.i("info","c<<3"+(c<<33));
33%32 为1,所以等于c<<1,所以c=16
int a=8;
a=a>>1;
Log.i("info","a="+a);
a=4
int b=-8;
Log.i("info","b>>2="+(b>>2));
b等于-2
Log.i("info","b>>>2="+(b>>>2));
b等于1073741822,相当于将原数据看成无符号数4294967288(fffffff8),再除4
int a=-100;
a=a>>2;
System.out.println(a);//-25
//255/2<<16=01111111 00000000 00000000
//255/2<<8= 01111111 00000000
//255/2 = 01111111
//color =(r<<16)+(g<<8)+b;
//int =(b1<<24)+(b2<<16)+(b3<<8)+b4; //数据的链接 //左移
【文字编码规则】
GBK 编码规则
A 变长编码 1~2字节
英文 1字节
中文 2字节
如:“ABC中国”->{byte*7}
B 支持的文字数量:中文+英文 20000+
C 中国本地最优编码
UTF-8编码规则
A 变长编码1~4字节
英文1字节
中文3字节
如:“ABC中国”->{byte*9}
B 支持文字数量:100000+
英文 中 日 韩 希伯来 阿拉伯。。。。等地球上有的
C 国际化最优编码
String s="ABC中国";
byte[] gbk =s.getBytes("GBK");//将字符串s中的字符按照“GBK”编码规则进行处理,
byte[] utf8 =s.getBytes("UTF-8"); //编码
System.out.println(gbk.length); //7
System.out.println(utf8.length); //9
String ss=new String(gbk,"GBK"); //解码
System.out.println(ss); //ABC中国
String s2= new String(utf8,"UTF-8"); //解码
System.out.println(s2); //ABC中国
String s3=new String(utf8,"GBK"); //解码成乱码
System.out.println(s3); //ABC涓浗
【二进制】
十进制转换为二进制
System.out.println(Integer.toBinaryString(210)); //11010010
当输入10进制时,java将输入的10进制字符串转换为2进制数据,保存到内部
当需要将内存数据显示给用户时,再利用算法将2进制转换为10进制的字符串显示
十进制到二进制 到16进制
int n =Integer.parseInt("250"); //字符串到整形 //自动调用 //字符串整形
System.out.println(Integer.toBinaryString(n)); //11111010//十进制到二进制
System.out.println(Integer.toHexString(156));//9c //10进制到16进制
//十进制转换为任意进制
String a=Integer.toString(111, 16); //整形到字符串 左边是数,右边是进制 //自动调用
System.out.println(a); //6f
//二进制转换为十进制 //任意进制转换为十进制
String x="111";
int y=Integer.parseInt(x, 2); //右边参数是进制 //转成10进制
System.out.println(y); //十进制7
System.out.println(Integer.toBinaryString(y)); //二进制111
int aa=-1;
aa=aa+(1024*1024*1024*2);
System.out.println(aa); //2147483647 //加半圈,等于相对的,绝对值相加等于同一个数
int cc=0;
cc=cc+(1024*1024*1024*2);
System.out.println(cc); //-2147483648 //加半圈
int bb=8;
bb=bb+(1024*1024*1024*2*2);
System.out.println(bb); //8 加一圈等于自己
int ii=-1;
System.out.println(Integer.toBinaryString(ii));//11111111111111111111111111111111
System.out.println(Integer.toBinaryString(2147483647)); //最大值01111111111111111111111111111111
System.out.println(Integer.toBinaryString(-2147483648));//最小值10000000000000000000000000000000
便捷书写二进制的-1
int i=0xffffffff; //-1
前面加0是8进制
007 //7
008 //错,8进制没有008,已经进位成010
0150 //104
【颜色】
JFrame f =new JFrame();
JPanel p =new JPanel();
int color=(int)(Math.random()*0xffffff);//16777215 //随机颜色
p.setBackground(new Color(0xff<<8)); //new Color(0xff<<8) 绿色
f.setSize(450,550);
f.add(p);
f.setVisible(true);
【InputStream与OutputStream】
【字节流】 //可以处理图片,音乐,文件等,使用的频率比字符流高 //都是Stream结尾
【InputStream与OutputStream】 //抽象类 //输入和读取要新建两个对象,output和input
【输入流】【输出流】 //不可能又读又写
什么是输入:输入是一个从外界进入到程序的方向,通常我们需要“读取”外界的数据时,使用输入。所以输入是用来读取数据的。
什么是输出:输出是一个从程序发送到外界的方向,通常我们需要”写出”数据到外界时,使用输出。所以输出是用来写出数据的。
//引用为null,不能调用任何方法,比如.close();
【节点流】和【处理流】 //流不为null 才能.close();
按照流是否直接与特定的地方 (如磁盘、内存、设备等) 相连,分为节点流和处理流两类。
节点流:可以从或向一个特定的地方(节点)读写数据。 //低级流 :真正帮我们来进行读写操作的流,来源(输入流)和去向(输出流)是明确的
处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。 //高级流 也分为输入流和输出流
处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
//高级流不能独立存在,必须基于另一个流进行工作,通常是对被处理流中的数据进行加工,以简化我们对读写的操作复杂度。
//高级流类似于连在水龙头上的净水器或热水器 //麦克风 喇叭
InputStream是所有字节输入流的父类,其定义了基础的读取方法,常用的方法如下:
int read()
读取一个字节,以int形式返回,该int值的”低八位”有效,若返回值为-1则表示EOF。
int read(byte[] d)
尝试最多读取给定数组的length个字节并存入该数组,返回值为实际读取到的字节量。
available()
获得剩余的可读取字节量
OutputStream是所有字节输出流的父类,其定义了基础的写出方法,常用的方法如下:
void write(int d)
写出一个字节,写的是给定的int的”低八位”
void write(byte[] d)
将给定的字节数组中的所有字节全部写出
write(byte[] d ,int from ,int n);
读取字节数组d从from开始的n个字节 //不是含头不含尾
【文件流】
创建FOS对象(重写模式) //低级流 //写入内容
FileOutputStream是文件的字节输出流,我们使用该流可以以字节为单位将数据写入文件。
构造方法 1:
FileOutputStream(File file)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
例如:
File file = new File("demo.dat");
FileOutputStream fos = new FileOutputStream(file);
构造方法 2:
FileOutputStream(String filename):
创建一个向具有指定名称的文件中写入数据的输出文 件流。
例如:
FileOutputStream fos = new FileOutputStream("demo.dat"); //创建文件,写入内容
这里需要注意,若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除。
创建FOS对象(追加模式)
通过上一节的构造方法创建的FOS对文件进行写操作时会覆盖文件中原有数据。若想在文件的原有数据之后追加新数据则需要以下构造方法创建FOS
构造方法:
FileOutputStream(File file,boolean append)
创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
例如:
File file = new File("demo.dat");
FileOutputStream fos = new FileOutputStream(file,true);
构造方法:
FileOutputStream(String filename,boolean append):
创建一个向具有指定名称的文件中写入数据的输出文 件流。
例如:
FileOutputStream fos = new FileOutputStream("demo.dat",true); //创建文件,写入内容
以上两个构造方法中,第二个参数若为true,那么通过该FOS写出的数据都是在文件末尾追加的。
FileOutputStream out =new FileOutputStream("d:\\f4");
out.write(97);
out.write(98);
out.write(93);
out.write(200);
byte[] buf ={100,101,102,103,104,105,106};
out.write(buf);
out.write(buf,2,5); //从下标2开始写5个
out.close();
创建FIS对象 //读取内容
FileInputStream是文件的字节输入流,我们使用该流可以以字节为单位读取文件内容。
FileInputStream有两个常用的构造方法:
FileInputStream(File file):
创建用于读取给定的File对象所表示的文件FIS
例如:
File file = new File("demo.dat");
FileInputStream fis
= new FileInputStream(file);//创建一个用于读取demo.dat文件的输入流
另一个构造方法:
FileInputStream(String name):
创建用于读取给定的文件系统中的路径名name所指定的文件的FIS
例如
FileInputStream fis
//创建一个用于读取demo.dat文件的输入流
= new FileInputStream("demo"); //不会创建文件
流的使用范例:
FileOutputStream fos =new FileOutputStream("fos.txt",true); //加true后,不会覆盖源文件的内容 //输出流
String str ="一马奔腾神雕摩擦摩擦是";
byte[] dat =str.getBytes("UTF-8"); //编码怎么放
//写入 fos.write(dat); //写入
fos.close(); //流使用完毕后要关闭,以释放底层C的资源
FileInputStream fis //创建一个用于读取demo.dat文件的 //输入流
= new FileInputStream("fos.txt");
byte[] buf =new byte[100]; //尝试读取100个字节,返回值为实际读取到的字节量
//读取 int len =fis.read(buf); //读取
String str1 =new String(buf,0,len,"UTF-8"); //编码怎么放
System.out.println(str);
fis.close();
FileInputStream in;
in=new FileInputStream("d:\\f4");
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
System.out.println(in.read());
in.close();
in=new FileInputStream("d:\\f4");
byte[] buf =new byte[20];
int a=in.read(buf);
String string=new String(buf,0,a);
System.out.println(string);
System.out.println(in.read(buf)+"我"+Arrays.toString(buf));
in.close();
用低级流来复制文件
一个字节一个字节的复制
FileInputStream fis
= new FileInputStream("fos.txt"); //输入流
FileOutputStream fos =new FileOutputStream("fos_copy.txt"); //输出流
int d=-1;
while((d=fis.read())!=-1){
fos.write(d);
}
System.out.println("文件复制完毕!");
fis.close();
fos.close();
10KB个字节的复制
FileInputStream fis
= new FileInputStream("fos.txt"); //输入流
FileOutputStream fos =new FileOutputStream("fos_copy.txt"); //输出流
byte[] buf =new byte[1024*10]; //10K
int d=-1;
while((d=fis.read(buf))!=-1){
fos.write(buf,0,d);
}
System.out.println("文件复制完毕!");
fis.close();
fos.close();
/**
*BOS与BIS
*缓冲字节输入与输出可以提高读写效率
*内部维护一个缓冲区,原理还是提高了读写的数据量减少
*读写次数来实现提高读写效率的
* */
【高级流】
用高级流(操作流)来复制文件,提高读取速度
*与其它流相接,
*)从其他流读取数据,处理后再返回数据
*)对输出的数据,处理之后,再向其他流输出
java.io.BufferedInputStream/BufferedOutputStream
*提高内存缓存区
*提高单字节读写效率
*Buffer流一个一个字节读取,会从相接的流,读取一批字节,放在内存的数组中
创建对象 //
FileInputStream fis =new FileInputStream("桌面.tar.gz");
BufferedInputStream bis =new BufferedInputStream(fis); //高级流 //可以有参,新建为new BufferedInputStream(相接的流,30*1024); //也可以无参(fis)(缓存为8k)
FileOutputStream fos =new FileOutputStream("桌面.tar_copy.gz");
BufferedOutputStream bos =new BufferedOutputStream(fos); //高级流
int d=-1;
long start=System.currentTimeMillis();
while((d=bis.read())!=-1){
bos.write(d);
}
long end =System.currentTimeMillis();
System.out.println("复制完毕!耗时"+(end-start)+"ms");//原先耗时644ms//用高级流后耗时48ms
bis.close(); //关高级流
bos.close(); //关高级流
【flush】方法
手动刷新一下缓存,close时会自动调用一次
out.flush();
【DataInputStream】【读写固定字节格式】
java.io.DataInputStream/java.io.DataOutputStream
*读写固定字节格式
创建对象
DataOutputStream out =new DataOutputStream(相接的流);
writeInt(int i);
writeDouble(double d)
writeUTF(String s);
DataInputStream
readInt(); //
readDouble(); //
readUTF();
例如:DataOutputStream out =new DataOutputStream(new FileOutputStream("/sdcard/stu",true));
System.out.println(out) //没有重写toString
【PrintStream】
例子:PrintStream out =new PrintStream(new FileOutputStream("d:\\f5"));
print(数据)
println(数据) 十六进制 十六进制 十进制0 = 十进制字符48 == 十六进制字符30
out.write(97); //00 00 00 61---->61
out.writeInt(97); //00 00 00 61---->00 00 00 61
十六进制字符
out.print(97); //00 00 00 61---->39 37 //改成了字符 //十六进制字符39= 十进制字符57= 十进制9
out.println(97); //00 00 00 61---->39 37 0D(换行符) //0A回车符现在已经没人用了
【System.out输出到控制台】
【字符编码】 encoding
【字符集】 charset
ASCll //美国
0-127
ISO-8859-1 //Latin-1 //西欧
159-255
GB2312 //中国
7k多个中文 不包含喆,镕
GBK //中国
20902个中文
英文单字节
中文双字节
UNICODE //统一码 万国码
70万以上
常用字符,双字节表示 //中英文都是双字节//通常用
生僻字符,三字节表示 //基本不用
java的char类型,采用的是unicode编码
中文window用gbk编码
手机上默认是utf-8
Unicode的传输码就是UTF-8 ,UTF-16Be ,UTF-16Le ,UTF-32
UTF-8:
英文:单字节
某些字符:双字节
中文:三字节
编码转换运算
Unicode-->其他编码
String s="abc中文";
byte[] a=s.getBytes(); //转成系统默认
byte[] a=s.getBytes("UTF-8"); //转成指定编码
其他编码-->Unicode
String s=new String(a,"UTF-8");
例子:
String s ="abc中文喆镕";
byte[] a;
a=s.getBytes();
System.out.println("默认:"+Arrays.toString(a));
a=s.getBytes("GBK");
System.out.println("GBK:"+Arrays.toString(a));
a=s.getBytes("UTF-8");
System.out.println("UTF-8:"+Arrays.toString(a));
输出:
默认:[97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70]
GBK:[97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70]
UTF-8:[97, 98, 99, -28, -72, -83, -26, -106, -121, -27, -106, -122, -23, -107, -107]
String s;
byte[] a;
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a);
System.out.println(s);
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a,"GBK");
System.out.println(s);
a=new byte[]{97, 98, 99, -42, -48, -50, -60, -122, -76, -23, 70};
s=new String(a,"UTF-8");
System.out.println(s);
a=new byte[]{97, 98, 99, -28, -72, -83, -26, -106, -121, -27, -106, -122, -23, -107, -107};
s=new String(a,"UTF-8");
System.out.println(s);
输出:
abc中文喆镕
abc中文喆镕
abc??????
abc中文喆镕
【字符流】 //主要用于文件,比如.txt文件 //只能处理文字,用的比字节流少 //都是Writer,Reader结尾
【Writer】【Reader】 //字符流抽象父类
java.io.Reader/Writer
读写字符数据
*字符流的抽象父类
方法
Writer
write(int c)
截取int末尾两个字节,作为字符输出
write(char[] buf)
write(char[] buf,int from ,int n) //从from开始,读取n个字符 //不是含头不含尾
write(String s)
Reader
read()
读取一个字符,补两个0字节转成int
read(char[] buf)
java.io.InputStreamReader/OutputStreamWriter
【InputStreamReader】 其他编码-->Unicode //转换流
【OutputStreamWriter】 Unicode-->其他编码
*编码转换流
创建对象
1. OutputStreamWriter out=new OutputStreamWriter(相接的字节流);
OutputStreamWriter out=new OutputStreamWriter(相接的字节流,编码);
例子:
InputStreamReader in;
in= new InputStreamReader(new FileInputStream("d:\\GHOSTERR.TXT"));
char[] buf =new char[8192];
int n;
while((n=in.read(buf))!=-1){
String s =new String(buf,0,n);
System.out.println(s); //把文件在控制台打印出来
}
in.close();
例子:复制
InputStreamReader in=new InputStreamReader(new FileInputStream(from),编码格式); //编码怎么放
OutputStreamWriter out=new OutputStreamWriter(new FileOutputStream(to),编码格式); //编码怎么放
char[] buf =new char[8192];
int n;
while((n=in.read(buf))!=-1){
out.write(buf,0,n);
}
in.close();
out.close();
【BufferedReader】 /bufferedWriter //字符缓冲
*字符缓冲
*提高单字符读写效率
创建对象
BufferedReader in =new BufferedReader(new InputStreamReader(new FileInputStream(from),编码)); //编码怎么放
方法:read() //读取单个字符。
方法 readLine() 读取一行字符串,不包含末尾的换行符 所以打印用的不是out.write,而是out.println。
读取结束,再读取,返回null
【PrintWriter】 //字符流 //与PrintStream相似
java.io.PrintWriter
*PrintStream、 只能与字节流相接
*PrintWriter 能接字符流,也能接字节流
创建对象:
PrintWriter out=new PrintWriter(new OutputStreamWriter(new FileOutputStream(to),编码)); //编码怎么放
out=new PrintWriter(new OutputStreamWriter(new FileOutputStream("d:\\dd.txt",true),"UTF-8"),true); //输出流
方法: 不覆盖 刷新
out.write(97);
out.writeInt(97);
out.print(97);
out.println(97);
【FileReader】 //字符流 //内部是"转换流"接"文件字节流"
java.io.FileReader/Writer
*内部是"转换流"接"文件字节流"
*不能指定编码
创建对象
FileReader out = new FileReader(文件)
【字节流】 //都是Stream结尾
【ObjectInputStream】【ObjectOutputStream】 //对象序列化,对象反序列化
java.io.ObjectInputStream
ObjectOutputStream out =new ObjectOutputStream(相接的流);
方法:
ObjectOutputStream
writeObject(Object obj) //序列化输出一个对象
ObjectInputStream
readObject()
学生类要序列化则要实现一个接口implements Serializable
标识接口
标识学生类,可以进行序列化
是个空接口,没有任何抽象方法
不序列化的成员
static 静态
transient 临时,暂时 //private transient int age; //很少用
序列化头部字节值
新建ObjectOutputStream时,会写入两个字节 AC ED //一个神奇字节,一个版本号
新建ObjectInputStream时,会读取头部字节值
序列化版本号
旧版本的序列化数据 //升级后就没用了。
不会恢复成新版本的类型
*定义版本
private static final long serialVersionUID=3L;
例子:
public static void test1()throws FileNotFoundException, IOException{
Student s=new Student(74,"张三","男",22);
ObjectOutputStream out =new ObjectOutputStream(
new FileOutputStream("d:\\f8"));
out.writeObject(s);
out.close();
}
public static void test2() throws FileNotFoundException, IOException, ClassNotFoundException{
ObjectInputStream in =new ObjectInputStream(
new FileInputStream("d:\\f8") );
Student s=(Student)in.readObject();
System.out.println(s);
in.close();
}
【ByteArrayOutputStream】 //读写字节数组中的数据 //方法:toByteArray()
创建对象、
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(baos);
DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:\\f9"));
DataOutputStream //固定字节格式
例子:写入
Student s =new Student(80,"张三","男",19);
//Student ss =new Student(50,"李斯","女",25); //无意义,没用
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos =new ObjectOutputStream(baos);
oos.writeObject(s);
//oos.writeObject(ss);
oos.close();
byte[] a=baos.toByteArray();
DataOutputStream dos=new DataOutputStream(new FileOutputStream("d:\\f9"));
dos.writeInt(a.length);
dos.write(a);
dos.close();
例子:读取
DataInputStream dis =new DataInputStream(
new FileInputStream("d:\\f9"));
int len =dis.readInt();
byte[] a=new byte[len];
dis.read(a);
dis.close();
ObjectInputStream ois=new ObjectInputStream(
new ByteArrayInputStream(a));
Student s=(Student) ois.readObject();
System.out.println("读取"+len+"个字节值,恢复成学生对象");
System.out.println(s);
输出:
读取139个字节值,恢复成学生对象
id:80
姓名:张三
性别:男
年龄19
【XML】
*可扩展的标记语言
*结构化的数据
*自描述的文件
*作用:
*)存储数据
*)传输数据
不能给普通用户看,由机器来处理
例子: //openwith --> XML Editor
<?xml version="1.0" encoding="UTF-8"?> //开头,版本,格式
//<!DOCTYPE email SYSTEM "email.dtd"> //引用DTD:
<!DOCTYPE email [ //DTD //email和 [] 要隔开
<!ELEMENT email (from,to subject,body)>
<!ELEMENT from (#PCDATA)> //#PCDATA纯文本
<!ELEMENT to (to-email+)>
<!ELEMENT subject (#PCDATA)>
<!ELEMENT body (#PCDATA)>
<!ATTLIST email
date CDATA #REQUIRED //必须有
time CDATA #IMPLIED //可选的
>
]>
<email date="2015-4-22" time="11:13:08"> //根元素,顶层元素,可自己设定,但只能有一个,
<from>aaa@aaa.com</from> //又开始,就要有结束
<to>
<to-email>bbb@bbb.com</to-email> //元素必须正确嵌套
<to-email>ccc@ccc.com</to-email> //<a k1="v1" k2=‘v2‘> 属性必须有属性值,属性值必须有引号,单引号双引号都可以
<to-email>ddd@ddd.com</to-email> //单引号内可以有双引号,双引号内可以有单引号
</to>
<subject>Hello XML</subject>
<body>
Hello XML!
XML 你好!
</body>
</email>
【属性】---Attribute
【文本】---text
子元素(和子元素内的文本)可以放在父元素的属性中,也可以作为子元素 //属性<email date="2015-4-22"> //文本<email> <子元素> 文本 </子元素> //安卓常用属性
复杂结构的文本,长文本,应该使用“文本”
【转义实体】
< <
> >
" "
‘ '
& &
【】 <![CDATA[ ]]>
机器从CDATA标签提取内容时,不做任何运算处理
所有内容作为普通字符提取出来
【注释】 <!-- -->
【标签】 Tag <a></a>
【元素】Element //从开始到结束
<to>
<to-email>bbb@bbb.com</to-email>
<to-email>ccc@ccc.com</to-email>
<to-email>ddd@ddd.com</to-email>
</to>
【DTD】
在特定的领域内定义的xml编写规范
由行业组织、领袖企业、技术领袖来制定DTD规范
引用DTD:
<!DOCTYPE email SYSTEM "email.dtd">
【Java处理XML】
SAX ---- Simple API for XML
DOM4J ---- Doctument Model Object for Java
XML PULL -- Android中集成的的开源API
【XPath】
========================================
* 用路径的形式,表示 xml 中的数据
/email/from
/email/to/to-email
/email/@date
/books/book/name
/books/book/authors/name
/books/book//name
//name
//@isbn
【【SAX】】
SaxParserFactory //工厂对象
*解析器工厂,辅助
创建对象
SaxParserFactory f=SaxParserFactory.newlnstance()
方法----
newSAXParser()
SaxParser
*sax解析器,读取并解析xml文档
创建对象
SaxParser p=工厂对象.newSAXParser()
方法
parse(文件,处理器对象)
parse(文件字节流,处理器对象)
parse(文件字符流,处理器对象)
DefaultHandler
*编写DefaultHandler的子类来处理sax解析器提取出来的数据 //新建子类继承它
方法
startElement() //处理开始标签数据
endElement() //处理结束标签数据
characters() //处理文本
例子:调用xml文件中开始标签,文本,结束标签
{
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
SAXParser p=SAXParserFactory.newInstance().newSAXParser();
EmailHandler h=new EmailHandler();
p.parse("E:\\workspace_1503\\day0100\\src\\day21\\email.xml", h);
}
static class EmailHandler extends DefaultHandler{ //匿名内部类
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("开始标签:"+qName);
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("结束标签:"+qName);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String s=new String(ch,start,length);
System.out.println("文本");
System.out.println(s);
}
}
}
输出:
开始标签:email
开始标签:from
文本
aaa@aaa.com
结束标签:from
开始标签:to
开始标签:to-email
文本
bbb@bbb.com
结束标签:to-email
.
.
.
【绝对路径】
* 有一个工具,可以用相对路径的方式,
* 获得文件的磁盘绝对路径”/”表示程序运行的目录
String path=Demo000.class.getResource("\\email.xml").getPath();
p.parse(path, h);
等于:
p.parse("E:\\workspace_1503\\day0100\\src\\day21\\email.xml", h);
【【DOM4J】】
*符合java编程习惯的DOM API
*第三方的开源API //不是java类库中有的 //需要导入dom4j-1.6.1.jar类库 和 jaxen-1.1-beta-6.jar
*将xml数据读入到内存,生成一个树状结构
SAXReader
String path =Test1.class.getResource("\\email.xml").getPath();
* SAXReader reader = new SAXReader();
/**
* 读取文件中的xml数据,生成dom树,Document对象,是树根。
* */
* Document doc = reader.read(path);
//获得根源树<email>
Element email =doc.getRootElement();
【SAX和DOM4J的区别】
*DOM4J占用更多内存资源
*解析大文件选择SAX //几百M
【【XML PULL】】 //Android推荐要重点掌握,以后使用最多 //pull解析
=================================
* 第三方开源 API
* android 开发库中,集成了 XML PULL
XmlPullParserFactory 工厂,用来创建解析器和序列化器
XmlPullParser 用来解析 xml
XmlSerializer 用来生成 xml
Xml 工厂辅助类,代替工厂来创建解析器和序列化器
【XmlPullParserFactory】
===================================================
* 工厂,用来创建解析器和序列化器
创建对象
------------------------------------
XmlPullParserFactory f =
XmlPullParserFactory.newInstance();
方法
------------------------------------
* newPullParser() 创建解析器 XmlPullParser
* newSerializer() 创建序列化器 XmlSerializer
【Xml】
==========================================
* 工厂辅助类,代替工厂来创建解析器和序列化器
方法
------------------------------------
Xml.newPullParser()
Xml.newSerializer()
【XmlPullParser】
==========================================
* xml pull 解析器
* 读取并解析提取 xml 文档中的数据
* 从头到尾,
一段一段的提取 xml 数据
创建对象
--------------------------------------
XmlPullParser p=Xml.newPullParser();
或
XmlPullParser p=XmlPullParserFactory.newInstance().newPullParser()
方法
--------------------------------------
setInput(Reader in)
setInput(InputStream in, String charset)
设置输入流,必须首先调用,以及设置编码格式比如"UTF-8"
next()
一次一次地,跳到下一段;
返回一个数字代码,表示当前位置的数据类型
如果文档结束,再向后跳,
返回 XmlPullParser.END_DOCUMENT (即数字1)
getEventType()
返回当前位置的数字代码
getText()
数字代码是 XmlPullParser.TEXT 时,
才能调用 getText() 方法,取出文本
nextText()
数字代码是 XmlPullParser.START_TAG 时,
才能调用 nextText(),跳到下一段取文本
相当于:
p.next();
p.getText();
getName()
数字代码是
XmlPullParser.START_TAG
XmlPullParser.END_TAG
时,才能调用 getName() 获得标签名
getAttributeCount()
获得这个标签内的属性数量
获得属性数量
getAttributeName(int index)
获得指定位置的属性名
getAttributeValue(int index)
获得指定位置的属性值
getAttributeValue(String namespace, String name)
用属性名,获得对应的属性值
*) 属性方法,必须在数字代码是
XmlPullParser.START_TAG 时,才能调用
【XmlSerializer】
=========================================
* 用来将数据序列化成 xml 格式的字符序列输出
创建对象
-------------------------------------
用 XmlPullParserFactory 或 Xml 类创建
XmlSerializer s =Xml.newSerializer(); //序列化器
方法
-------------------------------------
setOutput(Writer out)
setOutput(OutputStream out,String charset)
设置用来输出数据的流,
必须首先调用
startDocument(String encoding,boolean standalone)
用来输出头标签xml头标签
<?xml version="1.0" encoding="指定的编码" standalone="布尔值" ?>
standalone 参数:
true: 独立文档
false: 引用其他文档
startTag(String namespace,String name)
用来输出开始标签
namespace:命名空间
<t:student xmlns:t="http://www.tarena.com/sudents"> //网络路径可存在也可不存在
</t:student>
<n:student xmlns:n="http://www.newdongfang.com/sudents">
</n:student>
attribute(String namespace ,String name,String )
在开始标签中,输出属性,
必须在调用 startTag() 之后,调用 attribute()
text(String text)
在开始标签后面输出文本,
必须在调用 startTag() 之后,调用 text
endTag(String namespace,String name)
输出结束标签
必须在调用startTag()之后,调用endTag
cdsect(String text)
输出<![CDATA[]]之后,调用cdsect() // //.cdsect会结束,不会返回s,所以要用”;”来结束,再重新开始 //注意转义字符
comment(String text)
输出<!--注释 -->
flush()
【需要加权限】 //将数据序列化成xml格式的字符序列输出
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
【第二个老师】 //内容回顾
Day01-1 自我介绍
----------------------------------------------
齐雷
qilei@tarena.com.cn
QQ:67182745
----------------------------------------------
Day01-2 内容回顾 (编程基础)
1.基础语法
1)标识符(用户定义一些元素的名字)
2)变量(局部变量,参数变量,实例变量,类变量)
class Var{
int a;实例变量(每个对象都有一份)
static int b; 类变量(所有对象共享一份)
public void display(String str1){//参数变量
String str2;//局部变量
}
}按作用域划分为四种类型
3)语句
3.1)两大分支(if,switch)
3.2)三大循环(for,while,do{}while())
4)函数
4.1)实例方法(通过类的对象调用)
4.2)静态方法(通过类名)
无论实例方法还是静态方法都可以重载。
5)数组
5.1)一维数组: int[]a ,int []b;
5.2)多维数组
int a[][]={{1,2}};
int b[][][]={{{}},{{}}}
int c[][][][];
2.面向对象
1)两大对象(类对象Point.class,类的对象new Point())
2)三大特性 (封装,继承,多态)
3)两大对象关键字(this,super)
4)两大修饰符(static,final)
5)两大抽象(抽象类,接口)
6)四大内部类(实例内部类,静态内部类,局部内部类,匿名内部类)
3.API
3.1 基础API
1) 数学系列:(Number,Math,BigDecimal,Integer,.....)
2) 字符系列: (String,StringBuilder,StringBuffer,CharSequence)
3) 日期系列: (Date,Calendar)
3.2 集合API
1)Collection (List,Set,Queue,...)
2)Map (HashMap,TreeMap,....)
3)Iterator
4)Collections
3.3 IO流
1)输入(in): 读 (内存,外存(文件,数据库,网络))
|-->InputStream
|-->Reader
2)输出(out):写(内存,外存(....),)
|-->OutputStream
|-->Writer
3.4 XML
1)编写
2)解析(pull,sax,dom4j,.....)
扩展:
1)ctrl+shift+t
2)ctrl+o
3)ctrl+t
-----------------------------------------------
Scanner scan = new Scanner(System.in);
s = scan.nextLine(); //阻塞式方法
scan.close();
【局部内部类】
final Thread ta =new Thread(){ } //局部内部类想访问方法内的变量时,要用final修饰。 //不是成员
实例内部类
静态内部类,
局部内部类,
匿名内部类
【要求】
1.习惯于使用快捷键(提高写代码的速度)
2.习惯于独立的查询API。
3.习惯于课前预习,课后总结。
4.习惯于独立思考,创新。
【线程基础】
1.回顾Android底层架构?
Android 是一个平台,主要由四层构成:
Application(应用层):浏览器,支付宝,...
---------------------
Application Framwork (应用框架层): activity,service,...
---------------------
Libraries , Dalvik (虚拟机) :SQLite,....
---------------------
Linux kernal(内核):包含了大量的驱动
其中Linux 是使用C语言编写的操作系统,负责管理,调度所有硬件资源,并为应用软件提供一个可运行的平台。
Linux 系统是一个多任务操作系统,可以同时运行多个任务。
2.【进程】(Process)
进程通常可以理解为正在运行的程序,有自己独立的内存空间,由操作系统负责为其分配资源,
例如CPU的调度。多个进程可以并发执行。对于单个CPU,并发从宏观上理解是在同时执行,但在微观上是顺序执行。
3.【线程】(Thread)
线程是进程中的一个顺序的执行流(一个线程执行多个任务时,这多个任务是顺序执行的)
,一个进程可以启动多个线程,多个线程可以共享进程资源,并发执行。
4.【线程对象的创建?】
在Java中所有的线程对象的类型为Thread类型。我们创建线程对象的方式通常有两种:
1)创建Thread类的子类对象,重写Thread类的run方法,在此run方法中执行任务。
package day27;
public class ThreadDemo1 {
static void doMethod1(){
while(true){
String name=Thread.currentThread().getName();
System.out.println(name+"-->doMethod1");
}
}
/**想办法让此方法运行在自己创建的线程中*/
static void doMethod2(){
while(true){
String name=
Thread.currentThread().getName();
System.out.println(name+"-->doMethod2");
}
}
//此函数运行于JVM启动的一个main线程中
public static void main(String[] args) {
SubThread t=new SubThread();
t.start();//启动线程
doMethod1();
//doMethod2();
}
static class SubThread extends Thread{ //继承一个
@Override
public void run() { //重写run方法
doMethod2();
}
}
}
2)创建Thread类的对象,
调用Thread(Runnable r)构造方法。此时需要将要执行的任务写在r对象的run方法中。
package day27;
public class Test2 {
//static String s;
static class Task implements Runnable{
@Override
public void run() {
while (true) {
System.out.println("run()");
}
//s="hello";
}
}
public static void main(String[] args) {
//构建线程对象
Thread t=new Thread(new Task()); //新建一个
//启动线程对象,线程启动以后会自动执行task对象的run方法
t.start(); //先启动,不一定先执行,什么时候执行操作系统说了算
while(true){
System.out.println("main()");
}
//System.out.println(s.toUpperCase());
}
}
说明:线程对象创建以后不会自动执行,需要
调用Thread类的实例方法start()方法启动线程,
线程启动以后,如果获得了cpu会自动执行run
方法。
例子:匿名内部类
package day27;
import java.util.Scanner;
public class Test3 {
static String s;
public static void main(String[] args) {
/**
* 案例
* 1.在主线程构建两个工作线程
* 1.1.第一个线程:Thread类的子类(线程名位WorkA)
* 1.2.第二个线程:Thread类的对象,接收Runnable类型的任务(new Thread(任务)),
* 线程名位WorkB
* 2.线程A从负责从键盘输入一个字符串
* 3.线程B将线程A输入的字符串转换为大写输出
* 4.用匿名内部类写。
* */
ta.start();
tb.start();
}
static Thread ta =new Thread(){
@Override
public void run() {
System.out.println("请输入一组字符串");
Scanner scan =new Scanner(System.in);
s=scan.nextLine();
scan.close(); //关闭线程
}
};
static Thread tb=new Thread(new Runnable(){
@Override
public void run() {
while(s==null){}
System.out.println(s.toUpperCase());
}
});
}
FAQ? 【多线程的优势与劣势】
优势:提高效率,改善用户体验。
劣势:调试,维护会相对困难。
5.【线程对象的状态及相关方法的应用】
5.1 【线程状态】
1)新建状态(new Thread())
2)就绪状态(可运行状态)
3)运行状态(正在执行run方法)
4)阻塞状态(线程不可获得CPU)
5)死亡状态(线程已经运行结束)
5.2 【线程方法】
1)构造方法(重要)
2)setName(String name)
3)currentThread()
4)getName()
5)start() 启动线程,线程处于就绪状态
6)run() 在此方法执行业务逻辑,此时线程线程处于运行状态。
7)sleep(); 线程让出cpu处于阻塞状态
【休眠】
Thread.sleep(5000); //在不是继承了Thread的类中 //比如只是实现了Runnable
sleep(5000); //继承了Thread类的子类中,可以省略Thread.
8)interrupt();唤醒正在休眠的线程,被唤醒的线程处于就绪状态。
9)join()方法:调用此方法的线程优先执行。
10)setDaemon(boolean flag)
【守护线程】
当flag的值为true时,表示设置此线程为守护线程(精灵线程),可以将守护线程理解为服务
性线程。当没有其它线程在执行时(包括main线程也停止时),守护线程会自动销毁。
11)yeild()方法:让出cpu,但此线程处于就绪态。
12) isAlive() 判断线程是否还活着。
13) getState() 返回线程状态
14) setPriority() 设置线程优先级
----------------------------------------------
【线程的同步】
------------------------------
1.【何为线程同步?】
所谓线程同步通常可以理解为,多个线程在共享数据集上的互斥和协作。
FAQ?
1)多个线程并发执行
2)多个线程存在共享数据集
2.【线程同步的作用?】
1)保证线程安全(数据的安全)。
2)保证数据的合理性。
3.【线程的互斥?】
所谓线程互斥:
多个线程在共享数据集上排队执行。
【对象锁】
【如何实现?】
在共享数据集所在的代码块上添加一把锁,这个锁通常称之为对象锁。
获得锁的线程对象优先执行,其他线程等待。当获得了对象锁的线程执行完代码块会释放锁,其他线程
竞争锁,然后执行代码块。
代码中的实现:
1)【同步代码块】
synchronized (对象锁) { //主类.class //用这个省事
被锁的共享数据集
}
2)【同步方法】(默认同步锁是谁?)
public synchronized void sale(){
被锁的共享数据集
对象锁默认为this;
}
public static synchronized void sale(){
被锁的共享数据集
对象锁默认为类对象(例如TicketTask.class)
}
说明:我们使用加锁的方式实现了线程的互斥,保证了数据的安全,但同时也会降低系统的执行效率,
所以在一些线程安全的环境下尽量不要使用同步代码块或同步方法。
对synchronized(this)的一些理解
一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
二、然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。
三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
四、当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。
FAQ? //最近问到的问题
【】【】
1)StringBuffer与StringBuilder的
区别时什么?
StringBuffer是一个线程安全的StringBuilder,在很多方法上都
添加了synchronized关键字。
2)ArrayList与Vector的区别?
Vector是一个线程安全的ArrayList.
3)HashMap与HashTable的区别?
HashTable是一个线程安全的HashMap
4)Collections中的synchronizedXXX()系列
方法是将线程非安全的集合转换为线程安全的集合。
5)在线程非安全的环境或者高并发的环境
建议使用ConcurrentHashMap.
-----------------------------------
回顾:
对象构建过程?
Point p=new Point();
1)加载类(将类读到内存),存储到代码区(Code Area)在加载的过程中假如有静态
变量,静态代码块,它从上到下依次初始化。
2)为对象分配堆内存(随机分配)
3)在堆内存初始化实例变量(从上到下)
4)调用构造方法。
【类加载】
1.如果静态变量在静态块之上
则类加载时,先运行静态变量,再运行静态块
2.静态块只能访问静态成员
3.类加载时,不会加载静态内部类,在运行静态内部类时,才会加载它
【线程同步】【(线程协作)】
当多个线程在共享数据集上要实现交互操作,通常要借助object类中的
wait,notify,notifyall方法实现。
【wait】方法:调用此方法的线程会处于等待状态同时会释放对象锁。
【notify】方法:调用此方法用于通知具备相同锁对象的线程开始执行。同时调用此方法的线程会释放锁。 //等待之后被通知唤醒后不会再进行判断
【notifyall】方法用于通知多个具备相同锁的对象。
Object.class.wait();
Object.class.notify();
注意:
1) 这些方法要应用在同步代码块或同步方法内部
2) 这些方法由对象锁调用。
1)【何为池?】(程序中)
内存中的一块区域,假如这块区域中存储的是字符串,那可以将此池理解
为字符串池,假如是整数,那可以称之为整数池。
2)【线程池?】
在内存中有一块区域,这块区域中可以存储很多个线程,这些线程可以得到"重用"。
3)【使用线程池的目的?】
减少线程对象的创建次数,让我们的线程对象在程序可以得到重用,以提高系统的执行效率。
备注:线程池中线程的数量的多少取决于具体业务。
4)【Java中线程池的创建?】
1)Executors (借助此类的静态方法创建线程)
2)ExecutorService(线程池的管理者)
a)负责从池中取线程执行任务
b)负责将线程放回池中
c)关闭线程池。
例子:【es.execute(new Runnable() 】 //无返回值
//1.创建线程池
//1.1创建只有一个线程的线程池
ExecutorService es = Executors.newSingleThreadExecutor();
//1.2创建线程固定的线程池
ExecutorService es = Executors.newFixedThreadPool(10); //用得最多
//1.3创建一个上限数量没有限定的线程池
ExecutorService es =Executors.newCachedThreadPool();
//执行任务
es.execute(new Runnable() {
@Override
public void run() {
while(true){
String name=Thread.currentThread().getName();
System.out.println(name+"企鹅");
}
}
});
------------------------------------------------------------------------------
例子:【es.submit(new Callable】 //有返回值
System.out.println("输入一个数");
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
ExecutorService es = Executors.newSingleThreadExecutor();
Future<Integer> f=es.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum=1;
for(int i=1;i<=n;i++){
sum=sum*i;
}
return sum;
}
});
//阻塞主线程
int n=f.get(3,TimeUnit.SECONDS); //只等待3秒 //时间长了会崩溃
System.out.println("n="+n);
es.shutdown();
----------------------------------------
【线程任务调度】 //与时间有关
-------------------------------------------
1.何为任务调度?
所谓任务调度,就是操作系统为线程分配CPU执行任务。
分配CPU的方式通常有两种方式:
1)按时间片
2)按优先级
假设我们现在有一个需求,让CPU在某个时间去执行某个任务,那如何实现?
2. 【Timer类】在任务调度中应用?
对于任务数量比较少,比较简单的一些调用可以借助Timer类的对象实现。
如何实现?(实现步骤)
1)构建Timer对象?(看类型,看构造方法)
2)借助Timer对象的schedule方法执行任务,任务类型为TimerTask类型,将要执行的任务写到TimerTask对象的方法中。
3)任务结束以后,调用timer对象的cancel退出调度。
例子:
final Timer t=new Timer();
t.schedule(new TimerTask(){
@Override
public void run() {
String name=
Thread.currentThread().getName();
System.out.println(name+"-->helloworld");
t.cancel();
}
},2000);//2000为延迟时间(默认相对于当前时间)
2. 【ScheduledExecutorService类】在任务调度中应用?
ScheduledExecutorService接口继承ExecutorService,并此基础之上扩展了一些相关方法。
此接口类型的对象,用于管理一个线程池,可以通过线程池中的线程,执行任务。
假设要通过ScheduledExecutorService接口执行任务调度,首先要借助Executors的方法
构建ScheduledExecutorService的实现类的对象,然后借助此对象的相关方法再去执行任务。
例子:
ScheduledExecutorService es=Executors.newScheduledThreadPool(3);
class Task implements Runnable{
private String name;
public Task(String name){
this.name=name;
}
SimpleDateFormat sdf=new SimpleDateFormat("HH:mm:ss");
@Override
public void run() {
try{Thread.sleep(1000);}catch(Exception e){}
System.out.println( name+"-->"+sdf.format(new Date()));
}
}
es.scheduleAtFixedRate( //两次任务的调度时间间隔为period
new Task("A"),
1,//initialDelay //初始延迟
1,//period
TimeUnit.SECONDS);//下一次调度,可能上一次任务还没有结束
es.scheduleWithFixedDelay( //两次任务的调度时间为delay+任务执行时间
new Task("B"),
1,//initialDelay //初始延迟
1, //delay
TimeUnit.SECONDS);//下一次的任务调度,需要等待上一次的任务执行结束
}
---------------------------------------------
【重复新建】
List<Weather> list=null; //定义集合 //声明
list=new ArrayList<Weather>(); //新建集合 //初始化
Weather wea=null; //定义对象 //声明
wea=new Weather(); //新建对象 //初始化
list.add(wea); //把对象加入到集合中
wea=null; //把对象清零
【DeBug】
F5:进入方法
F6:下一步
F7:返回上一次调用
F8:跳入下一个断点
一张图片的String状态
<image>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
/EeP/wdsPh55c2BhFQAAAABJRU5ErkJggg==
【Touch事件处理】
Android中提供了ViewGroup、View、Activity三个等级的Touch事件处理。也就是说,这三个地方都有事件回调方法。Android事件传递机制【按键事件】
测试DEMO视图结构:
<com .orgcent.eventtest.EventLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#032d3d"
android:orientation="vertical" >
<com .orgcent.eventtest.EventTextView
android:id="@+id/tvEvent"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:gravity="center"
android:textColor="@android:color/black"
android:background="@android:color/white"
android:text="Activity - ViewGroup - View Event http://orgcent.com dispatch Test"/>
</com>
至于三者之间的执行顺序,将在下面详细阐述:
整体上看,事件传递顺序为ViewGroup::onInterceptTouchEvent() –> ViewGroup或View的onTouchEvent() –> Activity::onTouchEvent()
由于上面每个事件回调方法的返回值不同,导致事件本身及顺序发生微妙变化。下面以返回值为主线来详细阐述:
需要注意以下两点:
1、onInterceptTouchEvent()返回true,那么这个方法只会拦截动作ACTION_DOWN。
2、onInterceptTouchEvent()负责事件分发(事件传递方向),onTouchEvent()负责事件处理(消费)。
1、ViewGroup的onInterceptTouchEvent()
返回false:
默认实现方式。事件(按下、移动、抬起等)将直接传递给目标view(用户触摸的view)。
在ViewGroup触发,调用ViewGroup::onTouchEvent(),在View触发,调用View::onTouchEvent()。
androi-touch-event-1
PS:这里发现ViewGroup::onTouchEvent()也被调用了,原因是View::onTouchEvent()没有处理该事件(返回false),事件将交给父容器处理。
返回true:
表示ViewGroup将拦截子View的Touch事件。事件会直接传递到ViewGroup::onTouchEvent()处理。
也就是说,事件后面的移动、抬起动作不会经过onInterceptTouchEvent(),而是直接传到onTouchEvent()。
androi-touch-event-2
2、ViewGroup/View的onTouchEvent()
返回true:
表示事件按下动作被处理,意味着事件的移动、抬起等后续动作将会传到此方法。
如果是View处理,那么ViewGroup的onTouchEvent()将不会获得该事件。
androi-touch-event-3
PS:只要onInterceptTouchEvent()返回false,而且目标控件View::onTouchEvent()返回true,那么事件的每一个动作(按下、移动、抬起等)会都会首先传递到onInterceptTouchEvent()中。
如果是ViewGroup处理,那么Activity不会获得事件。
androi-touch-event-4
返回false:
表示View或ViewGroup不处理事件,系统将把事件传递给其父级处理。
如果View返回false,那么将由其父容器ViewGroup处理。如果ViewGroup不处理,最终将交给Activity来处理。
androi-touch-event-5
如果ViewGroup返回false,将交给最后一级Activity来处理。
androi-touch-event-6
3、Activity的onTouchEvent()
这个方法是事件最后被处理的地方。如果不处理,系统将抛弃这个事件。暂时没有发现这个方法的返回值对程序有什么意义。也许返回true能告诉系统事件被处理了。
标签:
原文地址:http://www.cnblogs.com/lipeineng/p/5205000.html