JAVASE笔记回顾
第一部分,JAVA基础和面向对象
part01 入门与开发环境搭建
1: 计算机基础知识(了解)
(1)计算机
(2)计算机硬件
(3)计算机软件
系统软件:windows,linux,mac
应用软件:QQ,YY,扫雷,CS/F
(4)软件开发
就是用开发工具和计算机语言做出软件
(5)计算机语言
人与计算机的交流方式
(6)人机交互
A:图像界面方便,简单,直观。
B:DOS 窗口方式要有控制台, 要记住很多的命令, 麻烦。
(7)键盘功能键和快捷键的介绍(掌握)
A:键盘功能键
tab
shift
ctrl
alt
空格
enter
windows 键
PrtSc
上下左右
B:键盘快捷键(补齐中文意思)
ctrl+A 全选
ctrl+C 赋值
ctrl+V 粘贴
ctrl+X 前切
ctrl+Z 撤销
ctrl+S 保存
(8)常用的DOS 命令
A:如何打开控制台
win+R -- cmd -- 回车
B:常用的命令
d:回车切换盘符
cd demo 回车进入目录
cd.. 返回上一级目录
cd\ 返回跟目录
cls 清屏
exit 退出
2: Java 语言概述
(1)Java 语言的发展史
Java 之父-- 詹姆斯·高斯林(James Gosling)
(2)Java 语言的平台
A:J2SE 基础版,桌面应用
B:J2ME 微型版,手机开发(android,ios)
C:J2EE 企业版,所有浏览器访问的应用程序。
注意:JDK5 以后改名JavaSE,JavaME,JavaEE
J2SE 是学习其他两门的基础。
(3)Java 语言的特点
其他的很多特点...
开源:源代码开放
跨平台:在任意操作系统下都可以使用。
(4)跨平台
通过火星人和中国,德国人的交流知道的原理,找一个翻译。而java 语言的这个翻译是jvm 。
注意:java 语言是跨平台的,jvm 不是跨平台的。
(5)JRE 和JDK(掌握)
JRE: JVM + class library 运行环境:虚拟机+核心类库
JDK: JRE + tools 开发工具包:运行环境+
一句话:有JDK 开发的软件,必须在JRE 上运行,并由JVM 保证跨平台。
3:JDK 的下载与安装(掌握)
(1)JDK 的下载。
通过官网: http://www.oracle.com
(2)JDK 的安装
A:傻瓜式安装, 会点击下一步即可。
B:注意:
a:请不要在中文目录和有特殊字符的目录(空格)
b:请把所有开发相关的软件放到一个目录中。
C:JRE 是不需要单独安装的。
4:HelloWorld 案例
(1)开发工具
A:记事本windows 自带的
B:高级记事本EditPlus
C:集成开发工具Eclipse/MyEclipse
(2)一个HelloWorld 案例
最终代码:
class Demo
{
public static void main(String[] args)
{
System.out.println("Hello World");
}
}
解释:
A:java 语言的最基本单位是类。用class 表示
定义类的格式:
class 类名
B:程序如果要运行, 就必须有main 方法, 它是被jvm 调用。
格式:
public static void main(String[] args)
C:程序如果要输出一些内容, 就必须使用输出语句。
格式:
S ystem.out.println("Hello World");
(3)一个Java 程序的执行。
A:开发源程序(.java 文件)
Demo.java
B:通过javac 命令编译(.class)
javac Demo.java
C:通过java 命令执行
java Demo
(4)常见的错误及注意事项
A:文件扩展名导致编译失败。把隐藏文件扩展名给显示出来。
win7,win8 的同学如果不会单独问我。
B:非法字符错误
只要看到是非法字符, 肯定是中英文问题。
因为我们要求所有的符号全部是英文状态的。
C:注意大小写问题
class -- Class
String -- string
System -- system
D:括号的对应问题
在java 程序中,括号都是成对出现的。
所以建议在编写程序时,请遇到括号,成对打。
E:main 方法格式错误
public static void main(String [] args){ }
F:当java 源文件发生变化后, 请重写编译在运行
G:缩进问题:写代码遇到{}缩进一个tab 位置。
5:环境变量
(1)path 环境变量的作用
让javac 和java 命令可以在任意的目录下使用。
(2)path 环境变量的配置(掌握)
A:只修改path
D:\develop\Java\jdk1.7.0_45\bin;以前的path
**B:先建立一个JAVA_HOME,后修改path**
新建:JAVA_HOME 值是D:\develop\Java\jdk1.7.0_45
修改:%JAVA_HOME%\bin;以前的path
推荐使用B 方案。
(3)classpath 环境变量的配置
让指定的class 文件在任意目录都可以被访问。
技巧: 在最左边配置一个;
这样做的好处就是能够先在当前目录下查找并执行。
part02 常量、数据类型与运算符
1:常量
(1)在程序的运行过程中其值是不可以发生改变的量。
(2)常量的分类:
1:字面值常量
1:整数常量
12,-23
2:实数常量
12.5,-65.43
3:字符常量
'a','A','0'
4:字符串常量
"hello"
5: 布尔常量
true,false
6:空常量null
2:自定义常量
(3)常量可以直接被输出。
2:进制
(1)是一种进位的方式,X 进制表示逢x 进1 。
(2)Java 中整数常量的表示
1: 二进制由0,1 组成。以0b 开头。JDK7 以后的新特性。
2: 八进制由0-7 组成。以0 开头。
3: 十进制由0-9 组成。默认就是十进制。
4: 十六进制由0-9, A-F(不区分大小写)组成, 以0x 开头。
(3)进制转换:
1: 其他进制到十进制
系数: 就是每一位上的数据。
基数: X 进制, 基数就是X 。
权: 在右边, 从0 开始编号, 对应位上的编号即为该位的权。
结果: 把系数*基数的权次幂相加即可。:
2: 十进制到其他进制
除基取余, 直到商为0, 余数反转。
3: 快速转换
1): 8421 码。
2): 二进制--八进制(3 位组合)
3): 二进制--十六进制(4 位组合)
3: 变量(掌握)
(1)程序的运行过程中, 在指定范围内发生改变的量。
(2)格式:
数据类型 变量名= 初始化值;
变形格式:
数据类型 变量名;
变量名= 初始化值;
举例:
方式1: byte b = 10;
方式2: byte b;
b = 10;
4: 数据类型(掌握)
(1)分类
基本类型: 4 类8 种。
引用类型: 类, 接口, 数组。(了解)
(2)基本类型
整型:
byte 1个字节
short 2个字节
int 4个字节
long 8个字节
浮点型:
float 4个字节
double 8个字节
字符型:
char 2个字节
布尔型:
boolean 不明确。可以认为是1 个字节。
注意:
整数默认是int 类型。long 类型需要加L 或者l 后缀。
浮点数默认是double 类型。float 类型需要加F 或者f 后缀。
(3)类型转换
1: boolean 类型不参与转换。
2: 隐式转换(从小到大)
byte,short,char -- int -- long -- float -- double
3: 强制转换(从大到小)
格式:(数据类型)数据;
(4)面试题
byte b1 = 3;
byte b2 = 4;
byte b3 = b1 + b2;
byte b4 = 3 + 4;//报错,int类型无法赋值给byte类型
5: 运算符(掌握)
(1)就是把常量和变量连接的符号, 一般参与运算使用。
(2)分类:
算术运算符
赋值运算符
关系运算符
逻辑运算符
位运算符
三元运算符
(3)算术运算符:+,-,*,/,%,++,--
+: 正号, 加法, 字符串连接符。
System.out.println("5+5="+5+5);//5+5=55
System.out.println(5+5+"=5+5");//10=5+5
%: 模运算, 取余数
左边如果大于右边, 结果是余数。
左边如果小于右边, 结果是左边。
左边如果等于右边, 结果是0 。
正负号跟左边一致。
++/--:
++ 其实相当于把数据+1
单独使用:在数据的前后, 结果一致。
参与操作使用:
如果在数据的后边, 数据先操作, 在++/--
如果在数据的前边, 数据先++/--, 在操作。
(4)赋值运算符
=,+=,-=,*=,/=,%=
int a = 10;
把10 赋值给int 类型的变量a 。
a += 20;
把左边和右边的和赋值给左边。
注意事项:
a = a + 20;
a += 20;
结果是等价的,效果不是等价的。
+=运算内含了强制类型转换功能。
比如:
s hort s = 2;
s+=3;
等价于
s = (short)(s+3);
(5)关系运算符
==,!=,>,>=,<,<=
特点: 关系运算符的结果都是boolean 类型。
请千万注意: == 不要写成=
(6)逻辑运算符
&,|,!,^,&&,||
&:有false 则false
|:有true 则true
!:true 变false,false 变true
^:相同false,不同true
&&:有false 则false
||:有true 则true
&&和&的区别是: 如果左边有false 了, 右边将不再执行。
||和|的区别是: 如果左边有true 了, 右边将不再执行。
开发中常用:
&&,||,?!(s+3)?;
part03 运算符与流程控制语句
1: 运算符(掌握)
(1)位运算符(了解)
^ : 一个数据对同一个数据^两次, 结果还是数据本身。
举例: a ^ b ^ b = a
(2)条件运算符
格式:
条件表达式?表达式1:表达式2
执行流程:
根据条件表达式返回的是true 还是false, 决定结果是什么。
如果是true,就把表达式1 作为结果。
如果是false,就把表达式2 作为结果。
举例:
int a = 100;
int b = a > 50 ? 200 : 100;
请问b 的值?200
2: 面试题(理解)
(1)请用最有效率的代码写出2 乘以8
2<<3
(2)请交换两个变量。
int a = 10;
int b = 20;
开发: 临时变量
int temp = a;
a = b;
b = temp;
面试: 位^运算符
a = a ^ b;
b = a ^ b;//即b=a^b^b=a
a = a ^ b;//即a=a^b^a=b
3: if 语句(掌握)
(1)用于做判断使用的。
常见于对某个范围进行判断, 或者几个变量进行判断, 还有就是boolean 表达式的判
断。
(2)格式:
A:第一种格式: 一种情况
if(条件表达式)
{
语句体;
}
执行流程:
如果条件表达式为true, 就执行语句体;
否则, 什么都不执行。
B:第二种格式: 两种情况
if(条件表达式)
{
语句体1;
}
else
{
语句体2;
}
执行流程:
如果条件表达式为true, 就执行语句体1;
否则, 就执行语句体2;
特殊:
可以和条件表达式在某些情况下进行替换。
一般是在赋值的情况下可以。
举例:
获取两个数中的最大值。
C:第三种格式: 多种情况
if(条件表达式1)
{
语句体1;
}
else if(条件表达式2)
{
语句体2;
}.
..
else
{
语句体n;
}
执行流程:
如果条件表达式1 为true, 就执行语句体1;
如果条件表达式2 为true, 就执行语句体2;
...否则, 就执行语句体n;
D:注意事项
a:什么时候时候哪一种if 语句。
第一种格式在判断条件为一种情况下使用。
第二种格式在判断条件为两种情况下使用。
第三种格式在判断条件为多种情况下使用。
b:每一种if 语句其实都是一个整体, 如果有地方执行了,
其他的就不执行了。
c:如果if 或者else 里面控制的语句体是一条语句, 是可以省略大括号的,
但是, 如果是控制多条语句, 就必须写上大括号。
建议: 永远写上大括号。
d:大括号和分号一般不同时出现。
E:作用域
所有变量的定义只在它所属的大括号内有效。
(3)案例:
A:根据键盘录入的成绩, 判断等级。
B:根据键盘录入的月份, 输出该月份所对应的季节。
4: switch 语句(掌握)
(1)用于做选择使用的。一般用于几个常量的判断。
switch 会把几个常量值直接加载到内存, 在判断的时候, 效率要比if 高。
所以, 针对几个常量的判断, 一般选择switch 语句。
(2)switch 语句的格式:
switch(表达式)
{
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
case 值3:
语句体3;
break;
...
default:
语句体n;
break;
}
A:针对格式的解释
switch:表示这里使用的是switch 语句, 后面跟的是选项。
表达式: byte,short,int,char
JDK5 以后可以是枚举(以后讲)
JDK7 以后可以是字符串(后面讲)
case:表示这里就是选项的值, 它后面的值将来和表达式的值进行匹配。
case 后面的值是不能够重复的。
break:
switch 语句执行到这里, 就结束了。
default:
当所有的case 和表达式都不匹配的时候, 就走default 的内容。
它相当于if 语句的else 。一般不建议省略。
B:执行流程
进入switch 语句后, 就会根据表达式的值去找对应的case 值。
如果最终没有找到, 那么, 就执行default 的内容。
C:注意事项:
a:default 整体可以省略吗?
可以,但是不建议。
b:default 的位置可以放到前面吗?
可以,但是不建议。
c:break 可以省略吗?
可以,但是不建议。
default 在最后, break 是可以省略的。
case 后面的break 可以省略, 但是结果可能有问题。
d:switch 语句什么时候结束呢?
就是遇到break 或者执行到程序的末尾。
(3)案例:
A:根据键盘录入的日期(1-7),输出对应的星期日期。
B:根据键盘录入的月份, 输出该月份所对应的季节。(选做)
5: Scanner 的使用(掌握)
(1)Scanner 是JDK5 以后设计的用来接收键盘录入数据使用的。
(2)目前我们要通过键盘录入int 类型数据,必须按照如下步骤:
A:导包
import java.util.Scanner;
B:创建对象,封装键盘录入
Scanner sc = new Scanner(System.in);
C:调用方法,获取数据
int number = sc.nextInt();
part04 循环结构
1: 循环(掌握)
(1)如果发现有很多重复的内容的时候就考虑使用循环改进代码,让代码看起来简洁了。
(2)循环的组成
A:循环体,就是要做的事情。
B:初始化条件:一般定义的是一个初始变量
C:判断条件:用于控制循环的结束。
D:控制条件:用于控制变量的变化。一般都是一个++/--操作。
(3)循环的分类:
A:for循环
for(初始化条件;判断条件;控制条件)
{循环体;}
执行流程:
a:先执行初始化条件;
b:执行判断条件
c:根据判断条件的返回值:
true:执行循环体。
false:就结束循环。
d:最后执行控制条件。返回到b 继续。
B:while循环:先判断再循环
初始化条件;
while(判断条件)
{
循环体;
控制条件;
}
执行流程:
a:先执行初始化条件;
b:执行判断条件
c:根据判断条件的返回值:
true:执行循环体。
false:就结束循环。
d:最后执行控制条件。返回到b 继续。
C:do...while循环:先循环再判断(循环至少执行一次)
初始化条件;
do{
循环体;
控制条件;
}while(判断条件);
执行流程:
a:先执行初始化条件;
b:执行循环体和控制条件;
c:执行判断条件
d:根据返回值
true:返回b。
false:就结束循环。
注意:
a:一般使用for循环或者while 循环,而且这两种循环是可以等价转换的。
b:do...while 循环至少执行一次循环体。
(4)案例: (掌握)
A:求5 的阶乘。
B:水仙花。
C:统计叠多少次, 能叠成珠穆朗玛峰的高度。
(5)循环嵌套: (理解)
A:也就是循环语句的循环体是一个循环语句。
B:通过输出
****
****
****
我们不断的改进。发现了一个问题:
外循环控制行数,内循环控制列数。
(6)案例: (理解)
A:正三角形
内循环的判断条件: y<=x
for(int x=0; x<5; x++)
{
for(int y=0; y<=x; y++)
{
System.out.print("*");
}
System.out.println();
}
B:倒三角形
内循环的初始化条件: y=x
for(int x=0; x<5; x++)
{
for(int y=x; y<5; y++)
{
System.out.print("*");
}
System.out.println();
}
C:九九乘法表
2: break 和continue(掌握)
(1)有时我们需要对循环进行一些控制终止,就用到两个关键字:
break 和continue
(2)特点:
A:它们都必须在循环中(break 还可以在switch 中) 。
一般在循环的判断中。
B:如果单独使用break 和continue,后面是不能有语句的。
(3)区别:
A:break 结束当前循环。
B:continue 结束本次循环,进入下一次循环。
(4)如何退出嵌套循环: (了解)
用带标签的循环。
格式:
标签名: for(){
for(){if()
{
break 标签名;
}
}
}
3:应用场景(总结)
(1)变量:发现有一个数据是变化的时候就用变量。
(2)if 语句:如果是一个范围的判断,boolean 类型的表达式的判断,几个数据的判断。
(3)switch 语句:几个数据的判断。一般这种情况有限选择switch 。
(4)for 语句:如果次数或者范围特别明确。(水仙花)
(5)while 语句:如果次数或者范围不明确。(珠穆朗玛峰)
part05 函数与数组
1: 函数(掌握)
(1)定义在类中,有特定功能的一段小程序。
(2)函数的格式:
修饰符 返回值类型 函数名(形参类型 形式参数1, 形参类型 形式参数2...)
{
函数体;
reutrn 返回值;
}
A:修饰符public static
B:返回值类型程序最终结果的数据类型
C:函数名其实就是函数的名称,方便我们调用。
D:参数
形参类型数据类型
形式参数就是接收实际参数的变量
实际参数就是实际参与操作的变量(常量)
E:函数体就是按照正常的逻辑完成功能的代码。
F:返回值就是程序的最终结果
G:reutrn 返回值哪里调用程序,return 就把结果返回到哪里。
(3)函数的特点:
A:函数与函数之间是平级关系。不能在函数中定义函数。
B:运行特点:函数只有被调用才会被执行。
(4)案例:
有明确返回值的例子:
A:求两个数据的和
B:求两个数据的最大值
C:比较两个数是否相等
void 类型例子:
A:nn 乘法表
B:根据给定的行和列输出一个*组成的长方形
(5)函数的调用
A:有明确返回值
a:单独调用一般没有意义。
b:输出调用但是如果想拿结果继续操作 就有问题了。所以,不好。
c:赋值调用推荐方式。
B:void 类型
单独调用
(6)函数重载
A:函数名相同,参数列表不同(个数不同,对应的类型不同) ,与返回值类型无关。
B:举例:
public static int sum(int a,int b){...}
public static int sum(int a,int b,int c){...}
public static int sum(float a,float b){...}
2: 数组(掌握)
(1)数组是存储同一种类型的多个元素的容器。
(2)好处:数组中的元素会被自动从0 开始编号,方便获取。
(3)格式:
A:int[] arr = new int[3];
B:int arr[] = new int[3];
C:int[] arr = new int[]{1,2,3};
D:int[] arr = {1,2,3};
推荐A 和D 。
(4)Java 内存图:
A:栈:存储局部变量使用,使用完毕立马消失。
B:堆:所有new 出来的都在堆里面。
a:每一个实体都有地址值
b:每一个实体内的内容都有默认值
整数:0
浮点数:0.0
字符:'\u0000'
布尔:false
c:在垃圾回收器空闲的时候被回收。
C:方法区
D:本地方法区
E:寄存器
(5)操作:
数组的索引:index
数组的长度:arr.length();
数组名
A:数组的遍历
for(int a:arr){操作a;}
B:数组获取最值:max();min();
C:数组的查找:二分查找
(6)二维数组:数组里面套了一层数组
格式:
A:int[][] arr = new int[3][2];
B:int[][] arr = new int[3][];
C:int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
遍历:
应用:遍历求和。
part06 面向对象
1: Java 中的参数传递问题
基本类型:形式参数的改变对实际参数没有影响。
引用类型:形式参数的改变直接影响实际参数,形参改变意味着地址值改变
2: 面向对象(理解)
(1)面向对象:是基于面向过程的一种思想。
面向过程:以函数为基础,关注实现过程。--具有某种功能的模块
面向对象:以对象为基础,关注实现结果。--具有某些功能的一个系统(有机整体)
(2)面向对象的思想特点:
A:是一种更符合人们思考习惯的思想。
B:把复杂的事情简单化了。
C:把我们从执行者变成了指挥者。
举例:
买电脑,洗衣,做饭,旅游。
(3)事物是如何体现的呢?
A:属性:有哪些特征
B:行为:有哪些功能
(4)类与对象的关系:
把事物转换成类:
A:成员变量
定义在类中方法外。
B:成员方法
和以前的区别是去掉static 。
类:是相关的属性和行为的集合,是一个抽象的概念。
对象:是某种事物的具体存在,是类的具体表现形式。
举例:
类:学生
对象:张三
(5)案例:
A:学生类
B:手机类
C:汽车类
(6)如何使用呢?
A:创建对象
格式:
类名 对象名= new 类名();(实际上是调用类的构造器来创建对象)
B:使用成员变量和成员方法
对象名.成员变量
对象名.成员方法
part07 面向对象的特征之一:封装
1: 封装(理解)
(1)隐藏实现的细节,提供公共的访问方式。
类,方法等其实都是封装的具体体现。
(2)private 关键字
A:用于修饰成员变量和成员方法。
B:被修饰的内容在其他类中是不可以被访问的。
(3)常见的应用:
类中的所有成员变量私有,给出对应的get/set 方法。
代码体现:
class Student
{
private String name;
private int age;
public Student(){}
public Student(String name,int age)
{
this.name = name;
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setAge(int age)
{
this.age = age;
}
public int getAge()
{
return age;
}
}
2: 构造方法(构造器)
(1)格式及特点
格式:
访问权限修饰符 类名(参数...){}
访问权限修饰符:
public,private
特点:
A:方法名和类名相同
B:没有返回值类型
C:没有具体的返回值
(2)注意事项:
A:如果你不给构造方法,jvm 会自动给你一个无参构造方法。
B:如果你给出了构造方法,那么jvm 将不再提供无参构造方法。
此时如果要使用无参构造方法:只能自己提供
推荐:永远手动给出无参构造方法。
3: this 关键字(掌握)
(1)是一个关键字。代表当前类对象的引用。
简单记:在方法中,哪个对象调用方法this 就代表谁。
除了静态方法外,所有的方法中有隐含的有一个this 引用
(2)应用场景:
解决局部变量隐藏成员变量问题。
4:static 关键字
(1)是一个关键字。可以修饰成员变量和成员方法。
(2)静态的特点:
A:随着类的加载而加载
B:优先于对象存在
C:被类的所有对象共享
D:可以通过类名调用
(3)静态的注意事项:
A:在静态方法中是没有this 关键字的。
B:静态方法只能访问静态成员。
(4)静态内容的调用:
A:被对象调用
B:被类名调用
推荐被类名调用。
(5)什么时候该用static 呢?
如果某个内容是所有对象共享的就用静态修饰。
举例:
水杯和饮水机。
厕所和人。
老师和学生。
5:Math 类的随机数(掌握)
类名调用静态方法。
包: java.lang
类: Math
方法: public static double random():
java.lang 包下的类是不用导包就可以直接使用的。
产生1-100 之间的随机数:
int number = (int)(Math.random()*100)+1;
part08 面向对象的特征之二:继承
1: 继承(掌握)
(1)把多个类中的相同的属性和行为进行抽取,封装到一个类中,然后再建立新类的时候,不需要从头做起,继承刚才定义的那个类即可。
(2)好处:
A:提高代码的复用性。
B:让类与类之间产生了一个关系,是多态的前提。
(3)什么时候使用继承?
A:如果类之间存在着:is a 的关系,就可以考虑使用继承。
B:不要为了继承部分功能,而去使用继承。
(4)继承的特点:
A:Java 只支持单继承,不支持多继承。(一个儿子只能一个爹)
为什么?如果支持多继承,就会出现调用不明确的问题。
B:Java 支持多层(重)继承。
(5)super 和this 的区别?
A:super 是一个关键字,代表父类的存储空间标识。(可以理解为父亲的引用)
B:它和this 的用法相似
a:成员变量
this.变量-- 本类的
super.变量-- 父类的
b:构造方法
this(...) -- 本类的
super(...) -- 父类的
c:成员方法
this.方法名() -- 本类的
super.方法名() -- 父类的
(6)子父类中成员变量的用法:
A:名称不同,这个太简单了。
B:名称相同,子类对象的在使用的时候:
先找子类局部范围
再找子类成员范围
最后找父类成员范围
(7)子父类中成员方法的用法:
A:名称不同,这个太简单了。
B:名称相同,子类对象的在使用的时候:
先找子类的
再找父类的
C:方法重写
在子类中,方法声明(修饰符,返回值,方法名,参数列表)相同的情况。
注意事项:
a:父类中私有方法是不能被重写
b:子类方法的访问权限一定要大于等于父类的访问权限
c:静态只能重写静态(静态跟类相关)
(8)子父类中构造方法的用法:
A:子类的初始化过程中,首先会去执行父类的初始化动作。
因为子类的构造方法中默认有一个super() 。
为什么?子类要使用父类的成员变量,这个初始化必须在子类初始化之前完成。
所以子类的初始化过程中会先执行父类的初始化。
B:如果父类没有无参构造方法
A:使用super 调用父类的带参构造。推荐方式。
B:使用this 调用本身的其他构造。
2: 代码块(面试题, 理解)
(1)执行顺序:
静态代码块(随着类的加载而加载)--> 构造代码块(每次创建对象时调用)--> 构造方法(初始化对象)
(2)注意事项:
静态代码块只执行一次
3:final(掌握)
(1)是一个关键字,可以用于修饰类、成员变量、成员方法。
(2)特点:
它修饰的类不能被继承。
它修饰的成员变量是一个常量。
它修饰的成员方法是不能被子类重写的。
part09 面向对象的特征之三:多态;抽象类、接口
1:多态(掌握)
(1)对象在不同时刻表现出来的不同状态。
举例:狗(狗、宠物、动物)
典型表现形式:用接口来接收类所创建的对象
(2)多态的前提
A:要有继承或者实现关系。
B:要有方法的重写/实现。
C:要有父类引用或者父接口引用指向子类对象。
注意:多态有三种体现形式:
类多态
抽象类多态
接口多态
(3)多态中的成员特点:
A:成员变量
编译看左边,运行看左边。
B:成员方法
编译看左边,运行看右边。
为什么?因为方法存在重写,而变量没有。
举例:孔子扮父。
(4)多态的弊端:
父类(接口)引用不能使用子类特有功能。
为了解决这个弊端需要向下转型。
Fu f = new Zi(); //向上转型
Zi z = (Zi)f; //向下转型
Zi z = new Zi();
(5)多态的好处:
可以提高代码的扩展性和可维护性。
2:抽象类:声明具有某些功能的一种类
(1)如果多个类中存在相同的方法声明,而方法体不一样,我们就可以只提取方法声明。
如果一个方法只有方法声明,没有方法体,那么这个方法必须用抽象修饰。而一个类中如果有抽象方法,这个类必须定义为抽象类。
(2)抽象类的特点
A:抽象类和抽象方法必须使用abstract 修饰
B:抽象类不能被实例化
C:抽象类有构造方法,用于子类实例化使用
D:如果一个类是抽象类,那么继承它的子类要么是抽象类,要么重写所有抽象方法。
(3)抽象类的成员特点
A:成员变量可以变量也可以是常量
B:拥有构造方法
C:成员方法可以有抽象方法也可以有非抽象方法(全是抽象方法或者非抽象方法都是可以的)
(4)抽象类的几个小问题
A:抽象类不能被实例化,为什么有构造?用于子类实例化使用。
B:一个类没有抽象方法,为什么定义为抽象类?不想被实例化,或者是抽取出来的一个规则类
C:abstract 不能和哪些关键字共存:final、private、static
3:接口(理解)
(1)如果一个抽象类中的方法都是抽象的, 这个时候, java 就提供了一种
更抽象的表示形式:----接口
接口:interface
实现:implements
格式:
interface 接口名{}
class 类名implements 接口名{}
(2)接口的特点:
A:接口不能被实例化。
B:一个类如果实现了接口:要么是抽象类、要么实现接口中的所有方法。
(3)接口的成员特点:
A:成员变量只能是常量(只能读不能改)。默认修饰符public static final
B:成员方法只能是抽象方法。默认修饰符public abstract
推荐:永远手动给出修饰符。
(4)接口的思想特点:
A:对外暴露的规则
B:是功能的扩展
C:降低耦合度
耦合:类与类的关系
内聚:类自己完成某件事情的能力
编程追求的目标:高内聚低耦合
D:接口可以多实现。
(5)类,接口的关系
A:类与类
继承关系,只能单继承可以多层继承。
B:类与接口
实现关系,可以单实现也可以多实现;还可以在继承一个类的同时实现多个接口。
C:接口与接口
继承关系,可以单继承也可以多继承。
(6)抽象类和接口的关系
接口是一种特殊的抽象类,比抽象类更抽象,接口里的方法全为抽象方法
part10 包、权限修饰符、内部类
1:包(掌握)
(1)包其实就是文件夹,用于区分相同的类名。
(2)格式:package 包名1.包名2...;
(3)带包的编译和运行
1:手动建包;2:自动建包
2:导包(掌握)
(1)一般来说用一个类,需要用该类的全路径名称。如果多个地方使用就比较麻烦,所以java 提供了导包操作。
(2)格式:
import 包名1.包名2...类名;
//下面这种属于把指定包下的类都导入。这种用法不推荐。我们应该用谁导谁。
import 包名1.包名2...*;
(3)package,import,class 的顺序
package -- import -- class
3: 四种权限修饰符(掌握)
4:注意,常见规则如下:
以后,所有的类都用public 修饰。并且在一个java 文件中只写一个类。
以后,所有的成员变量用private 修饰。
以后,所有的成员方法用public 修饰。
如果是抽象类或者接口:
public abstract + ...
以后,所有的构造方法用public 修饰。
如果类是工具类或者单例类:构造用private 修饰
5:内部类
(1)把类定义在一个类的内部。
(2)访问特点:
1:内部类可以直接访问外部类成员,包括私有
2:外部类要想访问内部类成员,必须创建对象。
(3)内部类分类:
1:成员位置:private 安全;static 方便调用
2:局部位置:定义在方法中
局部内部类访问局部变量必须加final 修饰,延迟生命周期。
(4)匿名内部类
1:是定义在局部位置的没有名字的内部类。
2:前提:存在一个类、抽象类或者接口。
3:格式
new 类或者接口名()
{重写方法;}
本质理解:其实这是一个继承类或者实现接口的匿名的子类对象。
4:使用
当你看到方法的形式参数是接口或者抽象类的时候,用匿名内部类改进。
匿名内部类只能使用一次,通常用来简化代码书写。
第二部分 常用API和集合
part11 IDE和Object类
Eclipse
1:Eclipse 的概述
(1)eclipse 的由来:由IBM 一个小组开发
(2)eclipse 的特点
A:完全由Java 语言编写的工具。
B:不需要安装
C:免费的:eclipse.org
D:开源的
E:扩展性非常强
(3)eclipse 和MyEclipse 的区别
A:MyEclipse 是基于eclipse 加入了一些用于开发Web 的插件并对这些自己开发的插件进行收费。
B:特点MyEclipse 集成性很好。
(4)在使用eclipse 之前,系统中必须要先有JDK 或者JRE 。
因为eclipse 就是用Java 语言编写的程序,所以需要jvm 的解释执行。
A:对于高版本的MyEclipse,内部已经集成了JDK 。所以安装后会用自己的JDK 来执行MyEclipse 。
2:Eclipse 安装
A:解压Eclipse 压缩包
B:复制到制定的目录(不要有中文、空格或其他非法字符)
3:Eclipse 的使用
A:打开软件的界面
B:新建一个项目(工程)
C:在项目下的src(源码包)下建立包
D:在包下建立类
E:在类里边写代码
F:编译源文件(代码写完保存的时候会自动生成class 文件, 在项目的bin 目录下。)
G:执行class 文件(右键-- Run As -- Java Application)
H:结果显示在Console 控制台上
4:Eclipse 的基本设置
A:在代码最左侧前面, 右键- Show Line Numbers, 如何取消?再次选择
B:java 代码字体,Window -- Preferences -- Appearance -- Colors and Fonts -- Java --
Java Editor -- 选择右边的Edit 进行修改即可。
C:如果不小心把界面给弄没了不要担心有复位操作,window -- reset ...
5:Eclipse 的内容辅助键
Alt+/
main 方法:先写main 然后alt+/最后Enter
输出语句:先写syso 然后alt+/最后Enter
for 循环:先写for 然后alt+/最后Enter
6:Eclipse 的快捷键
(A,E,F 必须掌握)
A:alt+/ 内容辅助键:补充类或者接口名,帮我们起变量名,new 后面直接提示等。
B:ctrl+/ 单行注释,在按一次,取消单行注释
C:ctrl+shift+/ 对选中的区域进行多行注释的封装
D:ctrl+shift+\ 用于取消多行注释,只要光标在多行注释中即可
E:ctrl+shift+o 对使用了其他包中的类或者接口进行自动导入
F:ctrl+shift+f 对代码进行格式化
G:alt+上键向上移动当前行或者选中行
H:alt+下键向下移动当前行或者选中行
I:ctrl+d 删除当前行,或者删除选中行
J:ctrl+shift+x 将选中部分的字母大写
K:ctrl+shift+y 将选中部分的字母小写
L:ctrl+1 光标放在编译中出现红色波浪线提示的内容上,在该快捷键可以获取建议的处理方式
M:F3 可以查看类或者方法的源码,前提是该原码已经关联。
7:Eclipse 的自动给出set,get 方法
右键--source--(set, get 方法)Generate Setters and Getters
(有参构造)Generate Constructor using Fields...
(无参构造)Generate Constructors form Superclass..
8:Eclipse 删除和导入项目
删除:选中项目-- 右键delete ...
A:从工作台中删除
B:从硬盘删除
导入:在项目所在位置的空白处右键--》Import --》General --》Existing Project...(最长的那个)
9:Eclipse 的debug 调试
A:如何加断点
在你想看从哪里执行的程序的左边双击即可。(不要在注释上做)
在哪里加?哪里不会加哪里,最好在每个方法的第一条语句上加。
B:如何使用
右键-- Debug As -- Java Application
弹出一个界面问你:是否打开调试界面。yes是否记住我的选择。选中框框即可
C:查看哪里
左边:程序运行到哪里了
右边:变量的变化过程
D:怎么继续:F6 执行一行。
E:去除断点
方式1:在点击的那个地方再次点击
方式2:在debug 调试界面--BreakPoints -- remove All...
F:补充:
F5 跳入;F8 跳到下一个断点
演示创建对象的整个过程
Object 类的方法
1:创建Student 对象并打印效果
A:打印他的时候,默认调用的他的toString 方法
B:Student 没有toString 方法,调用的是Object 的toString 方法
C:object 的toString 方法返回值是包名...类名+@+16 进制地址值,我们一般使用toString 方法都要重写他
2:关于==做比较的问题
A:基本类型的比较:比较的是值
B:引用类型的比较:比较的是引用类型所指向的地址值
3:自己实现对象的成员变量数据的比较
“2”,“3”目的是为了引出Object 中的equals 方法
4:Object 中的equals 方法
源码其实就是用“==”比较的两个变量或对象的引用
对于string和包装类,object类的equals()方法比较规则为:如果两个对象类型和内容一致则返回true;
也可自定义重写object的equals()方法:比如两个都是person类并且属性name也相同返回true。
5:String 类中的equals 方法
equals比较两个字符串是否一样
“==”比较的是变量或对象的引用
1: Scanner 注意事项
存在的问题:当录入数据依次是int String,并且分别使用nextInt()和next()方法获取数据的时候会接受不到String 数据。
解决办法:
1). 在录入完int 后重新创建一个新的Scanner 对象
2). 用字符串接受,然后把字符串转成int 类型
2:数据结构思想:拿时间换空间,拿空间换时间
例子: 需求:一个网站有一个功能,当填入你的年龄的时候就能自动判断你是哪个年龄段
0-9 岁, 儿童
10-19 岁, 少年
20-29 岁, 青年
30-39 岁, 壮年
40-49 岁, 中年
50-59 岁, 中老年
60 岁以上, 老年
代码实现例子:
String[] ages = {"儿童","少年","青年","中年","中老年","老年"};
System.out.println(ages[age/10]);
part12 常用API--String类
2: String 类(掌握)
(1)字符串:多个字符组成的一串数据。
(2)构造方法:
A:String s = new String();无参构造
B:String s = new String(byte[] bys);byte 数组转成字符串
C:String s = new String(byte[] bys,int index,int length);
从哪个地方截取byte 数组几个转成字符串(把字节数组的一部分转为字符串)
D:String s = new String(char[] chs);
字符数组转字符串(把字符数组的一部分转为字符串)
E:String s = new String(char[] chs,int index,int length);
从哪个地方截取char 数组几个转成字符串
F:String s = new String(String str);字符串里传一个字符串
G:String s = "hello";
(3)字符串的特点及面试题
A:字符串一旦被赋值就不能改变。
注意:字符串的值不能改变,没有说引用变量不能改变。
B:面试题:
a:String s1 = new String("hello")和String s2 = "hello"的区别。
s1是一个对象,存在于堆中,可以调用string类中的方法;s2是是一个字符串常量,不可以操作string类中的方法。
b:请写出结果:
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1==s2);//false地址值不一样
System.out.println(s1.equals(s2));//true内容一样
String s3 = new String("hello");
String s4 = "hello";
System.out.println(s3==s4);//false不具可比性
System.out.println(s3.equals(s4));//true内容一样
String s5 = "hello";
String s6 = "hello";
System.out.println(s5==s6);//true变量值一样
System.out.println(s5.equals(s6));//true
(4)成员方法
A:判断功能
boolean equals(Object obj):判断字符串的内容是否相同,区分大小写。boolean equals(obj)
boolean equalsIgnoreCase(String str):判断字符串的内容是否相同,不区分大小写。boolean equalsIgnnoreCase(str)
boolean contains(String str):判断字符串对象是否包含给定的字符串。boolean contains(str)
boolean startsWith(String str):判断字符串对象是否以给定的字符串开始。boolean startWith(str)
boolean endsWith(String str):判断字符串对象是否以给定的字符串结束。boolean endWith(str)
boolean isEmpty():判断字符串对象是否为空,数据是否为空。boolean isEmpty()
B:获取功能
int length():获取字符串的长度。int length()
char charAt(int index):返回字符串中给定索引处的字符。char charAt(index)
int indexOf(char ch):返回指定字符在此字符串中第一次出现的索引。int indexOf(ch)
int indexOf(String str):返回指定字符串在此字符串中第一次出现的索引。int indexOf(str)
int indexOf(int ch,int fromIndex):返回在此字符串中第一次出现指定字符的索引,从指定的索引开始搜索。
int indexOf(String str,int fromIndex):返回在此字符串中第一次出现指定字符串的索引,从指定的索引开始搜索。
String substring(int start):截取字符串,返回从指定位置开始截取后面的字符串。string substring(start)
String substring(int start,int end):截取字符串,返回从指定位置开始到指定位置结束截取后的字符串。
C:转换功能
byte[] getBytes():把字符串转换成字节数组。byte[] getBytes()
char[] toCharArray():把字符串转换成字符数组。char[] toCharArray()
static String copyValueOf(char[] chs):把字符数组转换成字符串。
static String valueOf(char[] chs):把字符数组转换成字符串。String valueOf(chs)
static String valueOf(int i):把int(基本类型)转换成字符串。String valueOf(int)
String toLowerCase():把字符串变成小写。String toLowerCase()
String toUpperCase():把字符串变成大写。String toUpperCase()
String concat(String str):拼接字符串。String concat(str)
D:其他功能
a:替换功能
String replace(char oldChar,char newChar):用新的字符去替换指定的旧字符。replace(oldCh,newCh)
String replace(String oldString,String newString): 用新的字符串去替换指定的旧字符串。
b:切割功能
String[] split(String regex):按照规定的格式切割字符串成字符串数组。string[] split(regex)//传入正则表达式
c:去除两端空格功能
String trim():去除字符串两端空格。string trim()
d:字典顺序比较功能
int compareTo(String str):按字典顺序(Unicode 编码顺序)如果第一个相同比较第二个依次类推。
int compareToIgnoreCase(String str) :按字典顺序( Unicode 编码顺序)如果第一个相同比较第二个依次类推不区分大小写
(5)案例
A:模拟用户登录(用到了判断equals 功能,如果有的用户名不区分大小写还可以用equalsIgnorCase)
String username = "admin";
String password = "admin";
// 三次机会
for (int x = 0; x < 3; x++) {
// x 0,1,2
// 键盘录入数据:用户名和密码。
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名: ");
String name = sc.nextLine();
System.out.println("请输入密码: ");
String pwd = sc.nextLine();
// 把数据进行比较。
if (username.equals(name) && password.equals(pwd)) {
System.out.println("恭喜你,登录成功");
// 引入曾经的猜数字小游戏。
break;
} else {
if ((2 - x) == 0) {
System.out.println("账号被锁定,请与站长联系");
} else {
// 2,1,0
System.out.println("登录失败,你还有" + (2 - x) + "次机会");
}
}
}
B:字符串遍历(用到了charAt 功能)
for (int x = 0; x < s.length(); x++) {
char ch = s.charAt(x);
System.out.println(ch);
}
C:统计字符串中大写、小写、数字字符出现的次数(用到了charAt 功能)
String s = "Hello12345World";
// 定义三个统计变量
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;
// 遍历字符串。
for (int x = 0; x < s.length(); x++) {
char ch = s.charAt(x);
// 判断是属于哪种范围
if (ch >= 'A' && ch <= 'Z') {
bigCount++;
} else if (ch >= 'a' && ch <= 'z') {
smallCount++;
} else if (ch >= '0' && ch <= '9') {
numberCount++;
}
}
D:把字符串的首字母大写,其他小写(用到了截取、连接、转大小写功能)
String str2 =str.substring(0,1).toUpperCase().concat(str.substring(1).toLowerCase());
E:大串中小串出现的次数(用到了截取、indexOf 功能)
public int getCount(String maxString, String minString) {
// 定义统计变量
int count = 0;
// 在大串中查找小串一次
int index = 0;
// 如果返回值不是-1,说明小串在大串中是存在的。
// 判断
while ((index = maxString.indexOf(minString)) != -1) {小串在大串中第一次出现的索引
// 统计变量++
count++;
// 把查找过的数据给截取掉,重新赋值给大串
maxString = maxString.substring(index + minString.length());
}
return count;
}
F:学习indexOf 过程中发现contains()的底层就是用的indexOf()
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
part13 常用API:Arrays、system、stringbuffer、interger
1:数组操作(理解原理,并要求会写该算法的代码)
1):冒泡排序原理:相邻元素两两比较,大的往后走,第一次完毕后最大值就在最大索引处。(升序)
2):冒泡排序代码
public static void bubbleSort(int[] arr) {
// 外循环控制次数
for (int x = 0; x < arr.length - 1; x++) {
// 内循环控制每一次的比较过程
/*
* 第一次,所有元素都参与比较,也就是0 个元素不参与。
* 第二次,有1 个元素不用参与。
* 第三次,有2 个元素不用参与。...
*/
// -1 是为了防止索引越界
// -x 是为了减少比较的次数
for (int y = 0; y < arr.length - 1 - x; y++) {
if (arr[y] > arr[y + 1]) {
// 数据交换
int temp = arr[y];
arr[y] = arr[y + 1];
arr[y + 1] = temp;
}
}
}
}
3):查找
--普通查找:数组无序
--二分查找(折半查找):数组有序
4):二分查找的代码:根据值查所在索引
public static int getIndex(int[] arr,int value)
{
int maxIndex = arr.length-1;
int minIndex = 0;
int midIndex = (maxIndex+minIndex)/2;
while(arr[midIndex]!=value){
if(arr[midIndex]>value)
{
maxIndex = midIndex - 1;
}
else if(arr[midIndex]<value)
{
minIndex = midIndex + 1;
}
if(minIndex > maxIndex)
{
return -1;
}
midIndex = (maxIndex+minIndex)/2;
}
return midIndex;
}
2:Arrays 工具类的使用
(1)Arrays 是针对数组操作的工具类。
(2)成员方法:
public static String toString(数组):把数组变成字符串。String toString(arr[])
public static void sort(数组):对数组进行排序(升序) 。void sort(arr[])
public static int binarySearch(int[] arr,int value):二分查找int binarySerch(arr[],value)
3:System 的方法(掌握)
(1)系统类提供了静态的变量和方法供我们使用。
(2)成员方法:
public static void exit(int value):退出jvm,非0 表示异常退出。void exit(value)
public static long currentTimeMillis():返回当前系统时间的毫秒值。(一般用来测试一个程序执行的快慢)
返回的是和1970 年1 月1 日午夜之间的时间差
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,intlength):从指定源数组中复制一个数组, 复制从指定的位置开始,到目标数组的指定位置结束。
4:StringBuffer:即可变长的String
(1)字符个数可以发生改变的字符串类,字符串缓冲区类。
(2)构造方法:
A:StringBuffer():默认容量16
B:StringBuffer(int capacity):指定容量
C:StringBuffer(String str):把字符串转换成StringBuffer
(3)成员方法:
A:添加功能
public StringBuffer append(int i):在末尾追加元素。StringBuffer append(int)
public StringBuffer insert(int index,int i):在指定位置添加元素。StringBuffer insert(index,int)
B:删除功能
StringBuffer deleteCharAt(int index):删除指定位置字符。StringBuffer deleteCharAt(index)
StringBuffer delete(int start, int end):删除指定开始位置和结束位置间的字符。StringBuffer delete(start,end)
C:替换功能
StringBuffer replace(int start, int end, String str):把开始到结束位置的字符用一个新的字符串给替换。
D:截取功能
String substring(int start):从指定位置到末尾截取。String substring(start)
String substring(int start, int end): 从指定位置到结束位置截取。
E:反转功能
StringBuffer reverse():字符串反转。StringBuffer reverse()
(4)案例:
字符串反转。
StringBuffer sb = new StringBuffer("abc");
sb.reverse();
String result = new String(sb);
System.out.println(result);//cba
5:基本类型包装类(掌握)
(1)基本类型的数据我们只能使用值,不能做更多的操作。为了方便我们操作java 就把每种基本类型进行了包装,提供方法供我们使用。
(2)基本类型和包装类的对应关系
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
(3)Integer 构造方法
A:Integer i = new Integer(int num);
B:Integer i = new Integer(String s);
注意:s 必须是一个由数字字符组成的字符串。
(4)String 和int 类型的转换
A:String -- int:parseInt(str)
Integer:public static int parseInt(String s)
B:int -- String:toString(int)/valueOf(int)
Integer:public static String toString(int i)
String:public static String valueOf(int i)
(5)JDK5 以后的新特性
A:自动装箱基本类型--引用类型
B:自动拆箱引用类型--基本类型
举例:
Integer i = 100;// 默认相当于new Integer(100)
i += 200;// 等价于i = new Integer(i.intValue()+200);
//因为i += 200 底层调用的是intValue()方法, 所以我们要加一层判断,防止报空指针异常
if (i != null) {
i += 200;
System.out.println(i);
}
(6)面试题:byte 常量池
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);// false
System.out.println(i1.equals(i2));// true
Integer i3 = new Integer(128);
Integer i4 = new Integer(128);
System.out.println(i3 == i4);// false
System.out.println(i3.equals(i4));// true
Integer i5 = 128;
Integer i6 = 128;
System.out.println(i5 == i6);// false
System.out.println(i5.equals(i6));// true
//byte 常量池。byte 范围内的值直接赋值给Integer,是从常量池里面获取的。
Integer i7 = 127;
Integer i8 = 127;
System.out.println(i7 == i8);// true
System.out.println(i7.equals(i8));// true
(7)案例:
把字符串中的数字字符排序。
需求:"23 98 16 38 42"
结果:"16 23 38 42 98"
代码:
String s = "23 98 71 54 60";
// 字符串转字符串数组
String[] strArray = s.split(" ");
// 字符串数组转int 数组(数字才可以比较大小,字符没法比较大小)
int[] arr = new int[strArray.length];//此时尚为空数组
// 循环遍历对arr数组依次赋值
for (int x = 0; x < arr.length; x++) {
arr[x] = Integer.parseInt(strArray[x]);
}
//int[]数组排序
Arrays.sort(arr);
//把排序后的int[] -- String
StringBuffer sb = new StringBuffer();
for(int x=0; x<arr.length ;x++){
sb.append(arr[x]).append(" ");//在sb字符串末尾追加元素
}
String result = sb.toString().trim();//去除字符串两端空格
System.out.println(result);
**:关于学习方法:
A:经常回顾,每次回顾都会有新的发现
B:经常练习
C:归纳总结错误
D:自学习惯锻炼自己独立思考问题的能力,用代码去实现你的思路。
**:面试题:随机给出一个数组,要求把越靠近50 的数往左排;
public static void main(String[] args) {
int[] arr = { 1, 2, 4, 7, 9, 12, 2, 3, 4, 89, 100, 105, 88, 50, 49, 48,
48, 47, 99, 60, 40, 30, 70 };
// int[] arr= {1,4,5,7,8,22,44};
arr = sort50(arr);
System.out.println(Arrays.toString(arr));
}
public static int[] sort50(int[] arr) {//靠近50的排序方法
// 从小到大排
Arrays.sort(arr);
/*
* 如果数组里面所有的数都大于50就返回原数组
*/
if (arr[1] >= 50) {
return arr;
/*
* 如果数组里面所有的数都小于50,
*/
} else if (arr[arr.length - 1] <= 50) {
int[] arrtemp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
arrtemp[arr.length - 1 - i] = arr[i];
}
return arrtemp;
/*
* 如果数组里面有大于50 的也有小于50 的
*/
} else {
// 外循环控制次数
for (int x = 0; x < arr.length - 1; x++) {
// 内循环控制每一次的比较过程
/*
* 第一次, 所有元素都参与比较, 也就是0 个元素不参与。第二次,有1
个元素不用参与。第三次, 有2 个元素不用参与。...
*/
// -1 是为了防止索引越界
// -x 是为了减少比较的次数
for (int y = 0; y < arr.length - 1 - x; y++) {
if (Math.abs(arr[y] - 50) > Math.abs(arr[y + 1] - 50)) {
// 数据交换
int temp = arr[y];
arr[y] = arr[y + 1];
arr[y + 1] = temp;
}
}
}
/*// 选择排序法
for (int i = 0; i < arr.length - 1; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (Math.abs(arr[i] - 50) > Math.abs(arr[j] - 50)) {
int temp = arr[j];
arr[j] = arr[i];
arr[i] = temp;
}
}
}*/
}
return arr;
}
part14 常用API:date、对象数组和综合案例
1:实际开发中常常遇到处理时间和日期的情况,Java中提供了date类来处理。
2:Date
(1)日期类。
构造方法:
Date():默认指当前系统时间。
Date(long time):根据给定的毫秒值生成一个时间。
(2)完成如下操作(日期和毫秒值的转换)
Date --> long:Date.getTime()
Date d = new Date();
long time = d.getTime();
long –> Date:Date的有参构造或Date.setTime()
long time = ???;
Date d = new Date(time);
或D
ate d2 = new Date();
d2.setTime(time);
(3)DateFormat 类(日期和字符串的转换)
String –> Date:日期格式对象.parse(string)
public Date parse(String source)
注意:如果是字符串到日期,你指定的格式必须和字符串的格式匹配。
2013-12-12
yyyy-MM-dd
2013/11/11
yyyy/MM/dd
Date –> String:日期格式对象 .format(date)
public final String format(Date date)
需要自己指定格式,常见的格式:
yyyy 年MM 月dd 日HH:mm:ss
yyyy 年MM 月dd 日
HH:mm:ss
yyyy-MM-dd HH:mm:ss
2: Calendar
(1)Calendar 是日历类,可以获取任意指定日历值,然后自由组合。
Calendar 是抽象类不能实例化,但是他提供了获取其实例的方法
Calendar c = Calendar.getInstance();// 多态
(2)成员方法:
get(日历字段):根据给定的日历字段获取值
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int date = c.get(Calendar.DATE);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);
String s = year + "年" + (month + 1) + "月" + date + "日" + " " + hour
+ ":" + minute + ":" + ((second>9)?second:"0"+second);
set(年,月,日):给日历设定指定的年, 月, 日
add(日历字段,值):给指定的日历字段添加或者减去给定的值。取决于值的正负。
(3)案例:请说出任意一年的2 月份是多少天。
Calendar c = Calendar.getInstance();
Scanner sc = new Scanner(System.in);
int year = sc.nextInt();
c.set(year, 3, 1);// 把日期设置为2013 年3 月1 日
c.add(Calendar.DATE, -1);// 把日期往前推1 日
System.out.println(c.get(Calendar.DATE));
3:对象数组
用以放置对象的数组
4:案例:对象数组改进登陆注册
UserDao:操作接口
UserDaoImpl:操作类实现操作接口
User:存储学生数据的对象(可以存储用户名, 密码, 邮箱等等)
UserTest:测试类
代码: 只给大家写一个UserDaoImpl 和UserTest,其他的比较简单
/**
* 用户操作实现类
**
如何实现呢? 如果是注册一个用户用User 保存即可。但是注册肯定不止一个用户, 所以我们得想想用什么存储?
目前我们学过的能够存储的:对象,对象数组。通过分析最终选择对象数组。但是这样做有问题:对象数组需要定义数组, 定义数组就得知道长度。可是无法确定数组长度。所以对象数组不够好。最终选择集合。不过集合还没学呢, 所以现在只能使用对象数组。自己给一个固定长度: 5
*/
public class UserDaoImpl implements UserDao {
// 定义成员变量的数组
private static User[] users = new User[5];//用户数组
private static int index = 0;
@Override
public boolean isLogin(String username, String password) {//登录
/*
* 遍历数组,获取到每一个对象,然后再拿对象的用户名和密码和传递过来的用户名和密码进行比较
*/
boolean flag = false;
for (int x = 0; x < users.length; x++) {
User user = users[x];
// 判断用户是否为null
if (user != null) {
//对比穿过来的用户名和密码
if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
flag = true;
break;
}
}
}
return flag;
}
@Override
public void regist(User user) {//注册
users[index++] = user;
}
}
----------------------------------------------------------------
import java.util.Scanner;
public class UserTest {
public static void main(String[] args) {
while (true) {
System.out.println("欢迎来到XXX");
System.out.println("1:登录");
System.out.println("2:注册");
System.out.println("3:退出");
System.out.println("请选择: ");
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
switch (line) {
case "1":
System.out.println("欢迎来到登录界面");
System.out.println("请输入用户名: ");
String username = sc.nextLine();
System.out.println("请输入密码: ");
String password = sc.nextLine();
UserDao ud = new UserDaoImpl();// 多态用法
// 具体类用法
UserDaoImpl udi = new UserDaoImpl();
boolean flag = udi.isLogin(username, password);
if (flag) {
System.out.println("开始玩游戏吧");
System.exit(0);
} else {
System.out.println("登录失败,返回主界面");
}
break;
case "2":
System.out.println("欢迎来到注册界面");
// 键盘录入用户信息
System.out.println("请输入用户名: ");
String newUsername = sc.nextLine();
System.out.println("请输入密码: ");
String newPassword = sc.nextLine();
System.out.println("请输入邮箱: ");
String newEmail = sc.nextLine();
System.out.println("请输入电话: ");
String newPhone = sc.nextLine();
// 把数据用对象进行封装
User user = new User();
user.setUsername(newUsername);
user.setPassword(newPassword);
user.setEmail(newEmail);
user.setPhone(newPhone);
// 创建用户操作类对象
UserDaoImpl newUdi = new UserDaoImpl();
// 调用注册方法
newUdi.regist(user);
System.out.println("注册成功");
break;
case "3":
// System.out.println("谢谢你的使用");
// System.exit(0);
// break;
default:
System.out.println("谢谢你的使用");
System.exit(0);
break;
}
}
}
}
part15 集合:cllection和list接口
1: 集合(理解)
(1)java 是一种面向对象语言,如果要针对多个对象进行操作就必须对多个对象进行存储,而对多个元素进行存储,数组有弊端---长度固定,数组将不能满足变化的要求,所以java 就提供了集合。
(2)集合的特点:
1、长度可以发生改变
2、只能存储对象
3、可以存储多种类型对象(一般存储的还是同一种)
(3)集合和数组的区别
1、长度问题
数组固定;集合可变
2、存储元素问题
数组可以是基本类型,也可以是引用类型;集合只能是引用类型。
3、是否同一类型
数组元素类型一致;集合元素类型可以不一致。
(4)集合体系的由来
集合是存储多个元素的容器,但是由于数据结构不同,java 就提供了多种集合类。而这多种集合类有共性的功能,所以通过不断的向上抽取最终形成了集合体系
结构。
数据结构:数据存储的方式。
程序= 算法+ 数据结构
(5)如何学习和使用一个继承体系呢?
学习顶层:因为顶层定义的是共性内容。
使用底层:因为底层才是具体的实现。
2: Collection 的功能(掌握)
(1)Collection 的功能
1、添加功能:add()
boolean add(Object obj):向集合中添加一个元素。
boolean addAll(Collection c):向集合中添加一个集合的元素。
2、删除功能:clear()/remove()
void clear():删除集合中所有的元素。
boolean remove(Object obj):删除集合中指定的元素。
boolean removeAll(Collection c):删除集合中指定的集合元素,只要有数据删除,则返回true 。
3、判断功能:isEmpty()/contains()
boolean isEmpty():判断集合是否为空。
boolean contains(Object obj):判断集合是否包含指定的元素。
boolean containsAll(Collection c):判断集合是否包含指定的集合中的元素。只有所有数据包含了才返回true 。
4、遍历功能:iterator迭代器
Iterator iterator():迭代器。
hasNext():判断是否还有元素
next():获取下一个元素
5、长度功能:size()
int size():获得集合的元素个数。
6、交集功能:retainAlll()
boolean retainAll(Collection c):判断集合中是否有相同的元素。如果有两个集合A 和B ,A 对B 做交集,A 集合保存的是交集元素,B 集合不发生改变,返回值表示的是A 集合是否发生过改变。
7、转换功能:toArray()
Object[] toArray():把集合变成数组。
(2)迭代器的使用
1、使用步骤
a、通过集合对象获取迭代器对象。
b、通过迭代器对象判断。
c、通过迭代器对象获取。
2、迭代器原理
由于多种集合的数据结构不同所以存储方式不同,所以取出方式也不同。此时就把判断和获取功能定义在了一个接口中,将来遍历哪种集合的时候只要该集合内部实现这个接口即可。
(3)集合的常见使用步骤:
1、创建集合对象
2、创建元素对象
3、把元素添加到集合中
4、遍历集合
a、通过集合对象获取迭代器对象。
b、通过迭代器对象判断。
c、通过迭代器对象获取。
(4)Collection 存储字符串和自定义对象并遍历。
1、存储字符串
Collection c = new ArrayList();//创建集合
//String s = "hello";
//c.add(s);
c.add("hello");//添加元素
c.add("world");
c.add("java");
Iterator it = c.iterator();//迭代器进行遍历
while(it.hasNext())
{
String s = (String)it.next();
System.out.println(s);
}
2、存储自定义对象
Collection c=new ArrayList();//定义集合
Student s1=new Student("林青霞",26);//定义元素
c.add("s1");//添加元素
Iterator it=c.iterator();//迭代器遍历
while(it.hasNext())
{
String s=(String)it.next();
System.out.println(s);
}
3: List 的特有功能
(1)List 的特点
List 是Collection 接口下的一个子接口
特点:元素有序可重复。
Set 也是Collection 接口下的一个子接口
特点:元素无序唯一。
(1)List 的特有功能
1、添加功能:add(index,obj)
void add(int index,Object obj): 在指定位置添加元素。
2、删除功能:remove(index)
Object remove(int index): 根据指定索引删除元素,并把删除的元素返回
3、修改功能:set(index,obj)
Object set(int index,Object obj):把指定索引位置的元素修改为指定的值,返回修改前的值。
4、获取功能:get(index)/indexOf(obj)/ListIterator--list迭代器
Object get(int index): 获取指定位置的元素
int indexOf(Object obj): 返回指定元素在集合中第一次出现的索引。
ListIterator listIterator():list迭代器
5、截取功能:subList(fromIndex,toIndex)
List subList( int fromIndex, int toIndex )截取集合。
(2)List 的遍历方式
1、Iterator 迭代器
2、ListIterator 迭代器(仅作了解)
3、普通for+get()
(3)ListIterator 迭代器
ConcurrentModificationException 并发修改异常
ConcurrentModificationException
①:为什么出现这个异常:因为我们在用迭代器遍历的时候,通过集合对元素进行了操作
②:如何解决呢:
A:通过迭代器遍历的时候,用迭代器进行操作集合元素ListIterator
B:普通for 循环遍历集合的时候,通过集合对元素进行操作
part16 集合:List实现类、泛型
1:常见的数据结构
栈,队列,数组,链表
栈:先进后出,类比水桶
队列:先进先出,类比出水管
数组:查询快(含有索引),增删慢
链表:查询慢(没有索引),增删快
扩展知识:
2: List 的三个儿子
(1)List 的三个儿子特点:
List
|--ArrayList
底层数据结构是数组,查询快,增删慢
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
(2)案例:ArrayList 存储自定义对象去重复
需求:ArrayList 如果存储的是学生,那么怎么去除重复元素呢?
问题:如何知道学生是重复的?
需求:如果学生的姓名和年龄相同,我就认为是同一个学生,即重复值。
问题分析:通过简单分析我们估计是判断那里出问题了。
看判断的方法。而我们又知道,判断的方法是API 提供的不是自己写的。所以看源码,通过看原码发现,底层依赖的是equals()方法。由于学生类中并没有equals()方法,所以默认用的是Object 的方法。而Object 类的方法,默认比较的是地址值。由于学生对象都是new 出来的地址值肯定不一样,所以从这个角度考虑结论是正确的。但是不符合我们的需求。怎么办呢?此时要重写equals()方法,让它按照我们的需求来比较。
代码:
public static void main(String[] args) {
ArrayList array = new ArrayList();
Student s1 = new Student("郑成功", 40);
Student s2 = new Student("戚继光", 50);
Student s3 = new Student("戚继光", 50);
Student s4 = new Student("岳飞", 36);
Student s5 = new Student("岳飞", 40);
Student s6 = new Student("林则徐", 30);
array.add(s1);
array.add(s2);
array.add(s3);
array.add(s4);
array.add(s5);
array.add(s6);
// 创建新集合
ArrayList array2 = new ArrayList();
// 遍历旧集合,获取到每一个元素
Iterator it = array.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
// 在新集合中判断, 看是否存在这个元素
if (!array2.contains(s)) {
// 如果s 不再array2 中存在就添加
array2.add(s);
}
}
// array2 就是没有重复元素的集合。
// 遍历array2
for (int x = 0; x < array2.size(); x++) {
Student s = (Student) array2.get(x);
System.out.println(s.getName() + "***" + s.getAge());
}
}
(3):Vector 的特有功能
A: 添加功能。
void addElement( Object obj )
B: 获取功能。
public Object elementAt( int index )
public Enumeration elements()//枚举:用于存储“稳定的”数据集
类Enumeration 里边有两个方法。(类似于迭代器)
boolean hasMoreElements()
Object nextElement()
public int size()
(4):LinkedList 的特有功能
A: 添加功能
void addFirst( Object o ):将指定元素插入此列表的开头。
void addLast( Object o ):将指定元素添加到此列表的结尾。
B: 获取功能
Object getFirst()
Object getLast()
C: 删除功能
Object removeFirst()
Object removeLast()
(5):面试题:用LinkedList 模拟栈数据结构
package cn.itcast_02;
A:第一步,自定义栈集合的类。
import java.util.LinkedList;
//自定义栈集合
public class MyStack {
//通过LinkedList 模拟栈数据结构
private LinkedList list;
public MyStack()
{
list = new LinkedList();
}
public void add(Object obj)
{
list.addFirst(obj);
}
public Object get(int index)
{
return list.get(index);
}
public int size()
{
return list.size();
}
}
B: 在测试类中测试。
package cn.itcast_02;
public class MyStackTest {
public static void main(String[] args) {
MyStack ms = new MyStack();
ms.add("hello");
ms.add("world");
ms.add("java");
for (int x = 0; x < ms.size(); x++) {
String s = (String) ms.get(x);
System.out.println(s);
}
}
}
(6)到底使用谁根据需求看
是否要安全:
是:Vector
否:ArrayList,LinkedList
查询多:ArrayList
增删多:LinkedList
如果什么都不知道用ArrayList 。
3: 泛型(理解)
(1)泛型是一种把明确类型的工作放在了创建对象或者调用方法时候才去明确的特殊的类型。
(2)格式:<数据类型>
(3)好处:
A:解决了黄色警告线问题
B:把运行期间的转换异常给提前到了编译期间
C:优化了程序设计,不需要做强制类型转换了
1):泛型类
需求:我能不能不用重载方法,就可以实现同一个方法输出不同类型的数据呢?
package cn.itcast_03;
//尖括号中的QQ 代表的是任意类型,QQ 也可以用其他任意字母代替(自定义)
public class Tool<QQ> {
//这里的QQ 必须和上边尖括号中的名字一样,qq 是变量名,可以自定义
public void show(QQ qq)
{
//输出QQ 类型的变量qq
System.out.println(qq);
}
}
2):泛型方法
为了保证方法传递不同的参数,就在类上明确了类型。这样的话,它要是能够在调用方法的时候,才去明确类型该有多好呢
public class Tool
{
public <BYD> void show( BYD byd )
{
System.out.println( byd );
}
}
3):泛型接口
A:定义Inter接口的代码。
package cn.itcast_03;
public interface Inter<BMW> {
public abstract void show(BMW bmw);
}
B:接口Inter 的实现类InterImpl 中的代码。
package cn.itcast_03;
public class InterImpl<BMW> implements Inter<BMW> {
@Override
public void show(BMW bmw) {
System.out.println(bmw);
}
4:增强for 循环
(1)格式:
for(数组或者Collection 集合的元素类型 变量: 数组或者Collection 集合的对象)
{
直接使用变量即可。
}
(2)好处:
方便了数组和Collection 集合的遍历。
(3)注意(注意):
A:增强for 是用来替代迭代器的。其底层就是调用的迭代器
B:不要在用增强for 遍历集合的时候,用集合对集合本身进行修改。
(4)遍历List 集合体系三种方式
1):迭代器
2):普通for+get
3):增强for(实际开发时时候用)
Collection 集合遍历两种方式
1):迭代器
3):增强for(工作时候用)
part17 集合:set实现类
面试题:用集合改进登陆注册案例
本次用集合改进“登陆注册”,仅仅是把包cn.itcast.dao.impl中的类UserDaoImpl 中的内容给修改了下。
public class UserDaoImpl implements UserDao {
//创建集合对象
private static ArrayList<User> array = new ArrayList<User>();
@Override
public boolean isLogin(String username, String password) {
// 遍历数组,获取到每一个对象,
// 然后再拿对象的用户名和密码和传递过来的用户名和密码进行比较
boolean flag = false;
//遍历集合获取每一个用户,如果存在就修改标记为true
for(User u : array)
{
if(u.getUsername().equals(username) &&
u.getPassword().equals(password))
{
flag = true;
break;
}
}
return flag;
}
@Override
public void regist(User user) {
//将该用户添加到集合中
array.add(user);
}
}
1:Set(掌握)
(1)Set 的特点:
元素无序唯一。(注意和List 的对比:元素有序可重复。)
注意:这里的顺序是指存储和取出顺序。
2:HashSet:保证唯一的方法---hashCode()和equals()
(1)HashSet:不保证元素的迭代顺序,且不保证该顺序恒久不变。
(2)怎么保证的呢?
HashSet 底层数据结构是哈希表。它依赖两个方法:hashCode()和equals()
顺序:
首先,判断hashCode()值是否相同。
相同:继续走equals()方法,根据其返回值:
true:说明元素重复,不添加到集合。
false:说明元素不重复,添加到集合。
不同:直接添加到集合。
(3)重写hashCode()和equals()方法:
hashCode():
把对象的所有成员变量值相加即可。
如果是基本类型就加值。如果是引用类型就加哈希值。
public int hashCode()
{
return this.name.hashCode() + this.age + this.sex +this.score ;
}
equals():
A:this==obj
B:!(obj instanceof Student)
C:所有成员变量的值比较,基本类型用==,引用类型用equals()
3:TreeSet:保证唯一的方法----实现comparable接口或comparator比较器接口
(1)TreeSet:根据构造方法的不用,选择使用自然排序或者比较器排序。按照实际的需求可对元素进行排序并且保证唯一。
(2)如何保证元素唯一的:
排序:底层结构是二叉树,按照树节点进行存储和取出。
两种实现:
A:自然排序(元素具备比较性):TreeSet 的无参构造,要求对象所属的类实现Comparable 接口。
public int compareTo( Studetn s )
{
//需求是比较年龄
int num = this.age - s.age ;
//由于对象有多个成员变量,不能根据其中的某一个决定其他的。
//当某一个相同的时候还需要判断其他的是不是也是相同的。
int num2 = ( num == 0 ) ? ( this.name.compareTo( s.name ) ) :
num ;
return num2;
}
B:比较器排序(集合具备比较性):TreeSet 的带参构造,要求构造方法接收一个实现了Comparator 接口的对象。
TreeSet<Student> ts = new TreeSet<Student> ( new
Comparator<Student>
{
@Override
public int compare ( Student s1 , Student s2)
{
//按照年龄排序从小到大
int num = s1.getAge() - s2.getAge();
//次要条件
int num2 = ( num == 0 ) ? (
s1.getName().compareTo(s2.getName()) ) : num;
return num2;
}
} );
//创建元素对象
Student s1 = new Student(“张三”, 24);
Student s2 = new Student(“李四”, 30);
Student s1 = new 。。。。。。
//添加元素
ts.add(s1);
ts.add(s2);
...........
for( Student s : ts )
{
System.out.println(s.getName() + "*****" + s.getAge());
}
唯一:根据返回值是否为0 。
注意:如果同时有两种方案以比较器为主。
(3)案例:TreeSet 存储自定义对象按照姓名长度排序
public int compareTo( Studetn s )
{
//需求是比较姓名的长度
int num = this.name.length() - s.name.length() ;
//很多时候,别人给我们的需求其实只是一个主要需求
//还有很多的次要需求是需要我们自己进行分析的。
//比较姓名的内容
int num2 = ( num == 0 ) ? ( this.name.compareTo( s.name ) ) : num ;
//继续分析,姓名长度和内容都相同的情况下,年龄还可能不一样
//所以当姓名长度和内容都相同的时候,再比较下年龄
int num3 = ( num2 == 0 ) ? ( this.age - s.age ) : num3 ;
return num3;
}
(4)原理:二叉树保证元素唯一排序
A:第一个添加的数据作为根节点。
B:从第二个开始,
每一个数据从根节点开始比较,
如果大了往右边放,如果小了往左边放,如果相同则替换。
C:从根节点开始,获取数据的规则:按照每个数据的:左,中,右原则。
4: Collection 体现的集合总结
Collection
|—List:元素有序可重复
|—ArrayList:底层数据结构是数组,查询快增删慢
线程不安全,效率高。
|—LinkedList:底层数据结构是链表,查询慢增删快
线程不安全,效率高。
|—Vector:底层数据结构是数组,查询快增删慢
线程安全,效率低。
|—Set:元素无序,唯一
|—HashSet:底层数据结构是哈希表。
保证元素唯一性:依赖两个方法---hashCode()和equals() 。
|—TreeSet:底层数据结构是二叉树。
保证元素唯一: 根据返回值是否是0,判断元素是否重复。
排序有两种方案:
元素具备比较性实现Comparable 接口
集合具备比较性实现Comparator 接口
5: 在集合中的数据结构问题
ArrayXxx:底层数据结构是数组,查询快增删慢
LinkedXxx:底层数据结构是链表,查询慢增删快
HashXxx:底层数据结构是哈希表,跟两个有关:hashCode()和equals()
TreeXxx:底层数据结构是二叉树:两种排序方式:Comparable 接口自然排序和Comparator 接口比较器排序
6: 什么时候,使用哪种Collection 集合。
元素唯一吗?
唯一:Set
需要排序吗?
需要:TreeSet
不需要:HashSet
不知道:用HashSet 。
不唯一:List
需要安全码?
需要:Vector
不需要:ArrayList 和LinkedList
查询多:ArrayList
增删多;LinkedList
不知道,用ArrayList 。
7:Collections工具类
(1)Collections 是针对Collection 集合操作的工具类。
public static void sort ( List list ):排序。
public static <T> int binarySearch( List list, T key ):二分查找。
public static void reverse( List list ):反转。
public static T max( Collection coll ):最大值。
public static void shuffle( List list ):随机置换(相当于“洗牌”)
(2)面试题:
Collection 和Collections 的区别?
Collection:是Collection 集合的顶层接口,定义了Collection 集合的共性方法。
Collections:是一个collection集合的工具类,定义了针对Collection 集合操作的功能,有排序、查找、反转等。
(3)案例:斗地主洗牌发牌小游戏
public static void main(String[] args) {
// 买牌
// 表示花色的数组
String[] colors = { "黑桃", "红桃", "梅花", "方块" };
// 表示点数的数组
String[] numbers = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10","J", "Q", "K" };
// 造一个牌盒
ArrayList<String> array = new ArrayList<String>();
array.add("大王");
array.add("小王");
// 循环装牌
for (String c : colors) {
for (String n : numbers) {
array.add(c.concat(n));
}
}
// 显示所有牌
// System.out.println(array);
// 洗牌
Collections.shuffle(array);
// 显示所有牌
// System.out.println(array);
// 发牌
ArrayList<String> linString = new ArrayList<String>();
ArrayList<String> zhouString = new ArrayList<String>();
ArrayList<String> meString = new ArrayList<String>();
// 用普通for
for (int x = 0; x < array.size() - 3; x++) {
if (x % 3 == 0) {
linString.add(array.get(x));
} else if (x % 3 == 1) {
zhouString.add(array.get(x));
} else if (x % 3 == 2) {
meString.add(array.get(x));
}
}
// 看牌
System.out.println("linString:" + linString);
System.out.println("zhouString:" + zhouString);
System.out.println("meString:" + meString);
// 看底牌
for (int x = array.size() - 3; x < array.size(); x++) {
System.out.print(array.get(x) + " ");
}
}
part18 集合:Map
1:Map
(1)Map 是一个键值对形式的集合,它的元素都是有键和值组成。
(2)Map 和Collection 的区别?(面试题)
A:Map 是由键值对组成的集合,Map 的键(key)是唯一的,值(value)可以重复。
B:Collection 是有单列数据组成的集合,它的儿子List 是可以重复的,Set 是唯一的。
(3)HashMap 和Hashtable 的区别?(面试题)
HashMap:线程不安全效率高,允许null 键和值。
Hashtable:线程安全效率低,不允许null 键和值。
(4)Map 的功能:
A:添加功能
V put(K key, V value) 当key 在集合中不存在时添加元素;当key 在集合中存在的时候替换元素。
B:判断功能
boolean containsValue( Object value ) 判断指定的值是否在集合中存在。
boolean isEmpty() 判断集合是否为空。
C:删除功能
void clear() 清除所有键值对数据。
V remove( Object key ) 根据指定的键删除键值对。
D:获取功能
Set<Map.Entry<K,V>> entrySet() 键值对对象的集合(注:entry登记,记录)
Object get( Object key ):根据键获取值。
Set<K> keySet():所有键的集合
Collection<V> values() 所有值的集合。
E:长度功能
int size()
(5)Map 的两种遍历方式
A:丈夫找妻子:根据键来找值
a:把所有丈夫给集合起来:Set<K> keySet()
b:遍历丈夫集合:获取到每一个丈夫:增强for 或迭代器
c:让丈夫去找妻子:get(Object key)
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
// 往集合里边添加元素
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
map.put("牛郎", "织女");
// 得到所有的丈夫对象
Set<String> husbandSet = map.keySet();
// 用迭代器的方式来做
Iterator it = husbandSet.iterator();
while(it.hasNext())
{
String husband = (String)it.next();
String wife = map.get(husband);
System.out.println(husband +"-----"+ wife);
}
// 用增强for 来做
for (String s : husbandSet) {
// 根据“丈夫”找到“妻子”--根据键获取值
String wife = map.get(s);
System.out.println(s + "******" + wife);
}
B:根据结婚证找丈夫和妻子:根据键值对来找键和值
a:获取所有结婚证的集合,Set<> entrySet()
b:遍历结婚证集合,获取到每一个结婚证对象:迭代器或增强for
c:通过结婚证对象获取丈夫和妻子getKey()和getValue()
// 创建集合对象
Map<String, String> map = new HashMap<String, String>();
// 往集合里边添加元素
map.put("郭靖", "黄蓉");
map.put("杨过", "小龙女");
map.put("牛郎", "侄女");
// 找到所有的“结婚证”即所有的键值对封装到一个集合中备用
Set<Map.Entry<String, String>> set = map.entrySet();
// 方式2 遍历,这样每次遍历我都会得到一个键值对
for (Map.Entry<String, String> en : set) {
// 得到键和值,然后打印
String key = en.getKey();
String value = en.getValue();
System.out.println(key + "****" + value);
}
2:HashMap
(1)HashMap 存储字符串并遍历
键:String
值:String
(2)HashMap 存储自定义对象并遍历
键:String
值:Student
(3)HashMap 存储自定义对象并遍历
键:Student(重写hashCode 和equals 方法,自动生成)
值:String
需求:如果对象的成员变量值都相同则认为是同一个对象。
3:TreeMap
(1)TreeMap 存储字符串并遍历
键:String
值:String
(2)TreeMap 存储自定义对象并遍历
键:String
值:Student
(3)TreeMap(传入一个比较器comparator)存储自定义对象并遍历
键:Student
值:String
需求:如果对象的成员变量值都相同则认为是同一个对象,同时还要按照年龄排序。
4:案例(理解)
(1)统计字符串中每个字符出现的次数。
//创建集合对象
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
String str = "cbxzbvavdvgd";
//将字符串转成字符数组
char[] chs = str.toCharArray();
//遍历字符数组
for (char ch : chs) {
//将拿到的字符去集合中找对应的值,根据返回值进行相应的操作
Integer i = tm.get(ch);
if (i == null) {
tm.put(ch, 1);
} else {
i++;
tm.put(ch, i);
}
}
//将得到的键值对集合,根据转变成字符串并将结果按照要求的格式打印出来
//创建可变字符串对象
StringBuilder sb = new StringBuilder();
//得到集合中所有的键并遍历
Set<Character> set = tm.keySet();
for(char ch:set)
{
//根据键找到对应的值, 然后按照要求的格式拼接
Integer i = tm.get(ch);
sb.append(ch).append("(").append(i).append(")");
}
//将结果转成字符串, 并输出
String result = sb.toString();
System.out.println(result);
(2)HashMap 嵌套HashMap 的使用。
//创建集合对象--czbk
HashMap<String,HashMap<String,String>> czbk = new
HashMap<String,HashMap<String,String>>();
//创建并添加元素对象yr 和jy
HashMap<String,String> yr = new HashMap<String,String>();
yr.put("01", "zhangsan");
yr.put("02", "lisi");
czbk.put("yr",yr );
HashMap<String,String> jy = new HashMap<String,String>();
jy.put("01", "wangwu");
jy.put("02","zhaoliu");
czbk.put("jy", jy);
//遍历集合
//创建集合对象--czbk
HashMap<String,HashMap<String,String>> czbk = new
HashMap<String,HashMap<String,String>>();
//创建并添加元素对象yr 和jy
HashMap<String,String> yr = new HashMap<String,String>();
yr.put("01", "zhangsan");
yr.put("02", "lisi");
czbk.put("yr",yr );
HashMap<String,String> jy = new HashMap<String,String>();
jy.put("01", "wangwu");
jy.put("02","zhaoliu");
czbk.put("jy", jy);
//遍历集合
//先拿到czbk 集合中所有的键, 并遍历
Set<String> czbkKeys = czbk.keySet();
for(String czbkKey :czbkKeys)
{
//打印czbk 集合中的键
System.out.println(czbkKey);
//在czbk 集合中, 根据键拿到对应的值, 因为值也是一个键值对集合, 所以我
们在遍历一次
HashMap<String,String> hm=czbk.get(czbkKey);
//拿到(czbk 的值集合)中的所有的键
Set<String> set = hm.keySet();
//遍历, 根据键找到对应的值, 并将结果输出
for(String s :set)
{
String value = hm.get(s);
System.out.println("\t"+s+"***"+value);
}
}
(3)HashMap 嵌套ArrayList 的使用。
part19 异常
异常
1:异常的概述
写完代码,代码下面有红线就是异常;运行程序控制台显示报错了,就是异常
2:异常的体系
Throwable
Error:严重的问题,通常出现的是重大的问题
比如运行的类不存在或者内存溢出等,不需要处理,但是肯定是要修改代码的(找到哪个地方有严重错误),
否则整个程序都运行不起来
Exception:不严重
编译期异常:强制要求我们处理
运行期异常:可以不处理,也可以处理
如果不处理:程序可以运行起来,但是运行到报错处
我们在编程的过程中肯定会有很多问题的存在
为了方便表示问题原因、类型、位置。java 就提供了异常对象供我们使用
异常:
程序出现的不正常情况
对应的异常
Throwable 类
---Error(错误)严重的
通常出现重大问题:运行的类不存在或者内存溢出,不需处理,而是需要修改代码
---Exception(异常)不严重的
---编译期间的,这个需要处理
---运行期间的,这个不需要处理的,需要修改代码或者传递参数
如果出现问题,我们自己没有处理,jvm 会才用的处理方式
他就是异常的类型原因、位置直接显示在控制台,后面的代码是不能执行的
A,编写处理代码:
基本格式
try{
可能发生问题的代码
}catch(异常类名,变量名){
异常处理代码
}
B,抛出
代码中有多个异常该怎么处理,一个个的用异常处理方案解决
针对所有问题写一个try catch,一个try 多个catch
注意:
在异常处理中,一旦try 里出问题了直接跳到catch 里处理
注意一个问题,异常或者错误都是以他们所在的体系父亲作为后缀
catch 顺序:
如果异常是平级关系没有顺序;如果有子父关系,父类要放在最后
**jdk7 新特性,多个catch 用一个处理
格式:catch(异常1 | 异常2 |、、、变量名){}
part20 递归
递归定义:方法定义调用方法本身的现象。
public void show(){
show();
}
注意事项:
A:递归一定要有出口,否则就会死递归。
B:递归的次数不要过多,否则内存溢出。
举例:
public void show(int n)
{
if(n==0)//出口条件,结束递归的条件
{
System.exit(0);
}
else{
System.out.println("hell");
show(n-1);
}
}
做递归的题思路
1)找递归出口
2)找递归规律
举例:用递归求5!
出口:1!=1
规律:n!=n*(n-1)!
public static int jc(int n) {
if (n == 1) {
// 出口
return 1;
} else {
// 规律
return n * jc(n - 1);
}
}
案例:用递归求斐波那契数列
public static int fun(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fun(n - 1) + fun(n - 2);
}
}
用递归求下列数列的第二十项的值: 1, 1, 2, 4, 7, 13, 24...
private static int sum(int i) {
if(i ==1){
return 1;
}else if(i==2){
return 1;
}else if(i==3){
return 2;
}else{
return sum(i-3) +sum(i-2)+ sum(i-1);
}
}
应用: 1:在控制台输出D:\jkdong\20160430 所有的java 文件的绝对路径。
private static void showFiles(File file) {
// 获取该目录下的所有文件或者文件夹的File[]数组。
File[] fileArray = file.listFiles();
//有时候一些有权限的文件不能获取, 所以fileArray 有可能为null 所以要
加入判断
if(fileArray!=null){
// 遍历File[]数组, 获取到每一个File 对象
for (File f : fileArray) {
// 判断该File 对数是否是目录
if (f.isDirectory()) {
showFiles(f);
} else {
// 文件
if (f.getName().endsWith(".java")) {
System.out.println(f.getAbsolutePath());
}
}
}
}
}
2:删除指定的目录(目录是带有目录或者文件的)
private static void deleteFiles(File file) {
//第1 步封装文件夹
File[] fileArray = file.listFiles();//1,test_deleteFiles; 2.1,aaa_deleteFiles;
2.2,bbb_deleteFiles;
if (fileArray != null) {
//如果封装的文件夹不为空,那么就进行遍历,获得每一个文件或文件夹
for (File f : fileArray) {
if (f.isDirectory()) {
//如果被封装文件夹的子文件还是个文件夹,那么继续封装起来
进行判断
deleteFiles(f);
} else {
//如果被封装起来的子文件夹正好就是个文件,那么直接删除
System.out.println(f.getName() + "***" + f.delete());
}
}
}
System.out.println(file.getName() + "***" + file.delete());
// 如果文件夹为空,直接删除. 当if 语句执行完时,就表示每次封装的目录下
的文件被删除完毕。
}
part21 IO 流
IO 流总结:
基本字符输出流:FileWriter
A:创建字符输出流FileWriter 对象(并传入一个写入的位置)
FileWriter fw = new FileWriter("a.txt");//必须初始化
B:调用写数据的功能
fw.write("hello,io你好");
C:刷新缓冲区
fw.flush();
D:释放资源(jvm 不会自动回收流的资源, 除非你手动标记该流已成为垃圾)
fw.close();
基本字符输入流:FileReader
//创建字符输入流对象(并且明确你要从哪个文件读数据)
FileReader fr = new FileReader("FileWriterDemo.java");
//方式1:一次读取一个字符
int ch = 0;
while((ch=fr.read())!=-1){//如果数据没有读取时将返回-1
//如果有数据则返回int 类型(字符的int 值),并自动移动到下一个数据位置等待读取
S ystem.out.print((char) ch);
}
//方式2:一次读取一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = fr.read(chs)) != -1) {//len 表示read(chs)读取到多少个字符
//如果实际读取长度是-1 的情况,那么说明已经读取到结尾了
System.out.print(new String(chs, 0, len));//new String(chs, 0, len)
//是为了写入实际读入的数据, 否则读取到最后的时候可能会有偏差
}
//释放资源
fr.close();
高效字符输出流:BufferedWriter
//创建高效字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));
// 写入数据
bw.write("hello");
bw.flush();
// 释放资源
bw.close();
高效字符输入流:BufferedReader
BufferedReader br = new BufferedReader(new FileReader("c.txt"));
// 方式一:一次读取一个字符
int ch = 0;
while ((ch = br.read()) != -1) {
System.out.print((char) ch);
}
// 方式二:一次读取一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = br.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
//方式3:一次读取一行
String line = null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
// 释放资源
br.close();
基本字节输出流:FileOutputStream
A:创建字节输出流对象
FileOutputStream fos = new FileOutputStream("a.txt");
B:调用写数据的方法
fos.write(97);
C:释放资源
fos.close();
注意:写数据的方法有
write(byte b)
write(byte[] bys);
write(byte[] bys, int start,int lenth);
追加写入用两个参数构造
FileOutputStream fos = new FileOutputStream("a.txt",true);
基本字节输入流:FileInputStream
FileInputStream fis = new FileInputStream("b.txt");
//方式1:一次读一个字节
int by = 0;
while ((by = fis.read()) != -1) {
System.out.println(by);
}
//方式2:一次读一个字节数组
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
//释放资源
fis.close();
高效字节输出流:BufferedOutputStream
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("4.mp4"));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\11.java"));
byte[] bys = new byte[1024];
int len = 0;
while((len=bis.read(bys))!=-1){
bos.write(bys,0,len);
}
bos.close();
bis.close();
高效字节输入流:BufferedInputStream
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
"d:\\copy.java"));
byte[] bys = new byte[1024];
int len = 0;
while((len=bis.read(bys))!=-1){
System.out.print(new String(bys, 0, len));
}
bis.close();
注意:对于文本可以用字符流也可用字节流,对于二进制数据(图片,音频,视频等)只能使用字节流
题目实例:
1: 复制MP3 加入异常处理的标准代码
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream("d:\\Copy.java"));
bos = new BufferedOutputStream(new FileOutputStream("copy1.java"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2: 键盘录入数据写入文本文件
// 封装数据源
Scanner sc = new Scanner(System.in);
// 封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("sc.txt"));
String line = null;
while((line=sc.nextLine())!=null){//"null"
if("over".equals(line)){
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
sc.close();
3: 在ArrayList 里面存储了3 个字符串元素, 请把这三个元素写入文本文件。并在每个元素
后面加入换行
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
BufferedWriter bw = new BufferedWriter(new FileWriter("array.txt"));
//遍历集合
for(String str : array){
bw.write(str);
bw.newLine();
bw.flush();
}
bw.close();
4:从集合读取数据写入到文件
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
ArrayList<String> array = new ArrayList<String>();
String line = null;
while ((line = br.readLine()) != null) {
array.add(line);
}
br.close();
// 遍历集合
for (String s : array) {
System.out.println(s);
}
5: 编写复制文件的工具类
/**
**
@author itcast 工具类, 专门用于复制文本文件, 图片等
*/
public class Copys {
private Copys() {
}//工具类的构造方法一般私有, 不允许new
/**
* 复制文本文件
**
@param src
* 数据源
* @param dest
* 目的地
*/
public static void copyFile(String src, String dest) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(src));
BufferedWriter bw = new BufferedWriter(new FileWriter(dest));
char[] chs = new char[1024];
int len = 0;
while ((len = br.read(chs)) != -1) {
bw.write(chs, 0, len);
bw.flush();
}
bw.close();
br.close();
}
/**
* 复制二进制流数据
**@param src
* 数据源
* @param dest
* 目的地
*/
public static void copyBinaryData(String src, String dest)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
src));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(dest));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
}
6:综合题:将d:\java 目录下的所有.java 文件复制到d:\jad 目录下, 并将原来文件的扩展名从.java 改为.jad
方法一:先改名再复制
// 封装d:\\java 这个目录
File srcFile = new File("d:\\hellodong");
// 获取该目录所有满足条件的File[]数组。
File[] fileArray = srcFile.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
System.out.println(dir+"---"+name);
return new File(dir, name).isFile() && name.endsWith(".java");
}
});
//判断是否存在目的地目录, 如果没有, 就创建。
File destFile = new File("d:\\jad");
if(!destFile.exists()){
destFile.mkdirs();
}
// 遍历File[]数组, 获取到每一个File 。
for (File file : fileArray) {
// file -- d:\\java\\Constant.java -- 数据源
//最终的结果: d:\\jad\\Constant.jad -- 目的地
//复制前改名
String name = file.getName(); //Constant.java
String newName = name.replace(".java", ".jad");//Constant.jad
File newFile = new File(destFile,newName);//d:\\jad\\Constant.jad
//复制文件
BufferedReader br = new BufferedReader(new FileReader(file));
BufferedWriter bw = new BufferedWriter(new FileWriter(newFile));
String line = null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
方法二: 先复制后改名
// 封装d:\\java 这个目录
File srcFile = new File("d:\\java");
// 获取该目录所有满足条件的File[]数组。
File[] fileArray = srcFile.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && name.endsWith(".java");
}
});
// 判断是否存在目的地目录, 如果没有, 就创建。
File destFile = new File("d:\\jad");//"d:\\jad\\ChangeNameDemo.java"
if (!destFile.exists()) {
destFile.mkdir();
}
// 遍历File[]数组, 获取到每一个File 。
for (File file : fileArray) {
//file -- d:\\java\\Constant.java
String name = file.getName();//Constant.java--》d:\\java\\Constant.java
File newFile = new File(destFile, name); //d:\\jad\\Constant.java
BufferedReader br = new BufferedReader(new FileReader(file));
BufferedWriter bw = new BufferedWriter(new FileWriter(newFile));
String line = null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
//复制完毕后改名
File[] destFileArray = destFile.listFiles();
for(File file : destFileArray){
//file -- d:\\jad\\Hello.java
//结果-- d:\\jad\\Hello.jad
String name = file.getName(); //Hello.java
String newName = name.replace(".java", ".jad");//Hello.jad
File newFile = new File(destFile,newName);//d:\\jad\\Hello.jad
file.renameTo(newFile);
}
part22 其它流、编码表、properties
转换流
1:标准的输入输出流
public static final InputStream in
System.in -- InputStream (字节输出流) 底层是BufferedInputStream
public static final PrintStream out
System.out -- PrintStream (字节输入流)
注意: 必须通过标准输入流才能从控制台录入数据
必须通过标准输出流才能把数据写入控制台显示
2.字节输入流转成字符输入流
方法:
字节流通向字符流的桥梁
InputStream --> InputStreamReader --> BufferedReader
3:字节输出流转字符输出流
方法:
OutputStream -- > OutputStreamWriter --> BufferedWriter
4:编码问题
流的编码问题:字符流=字节流+编码表
如果你想在IO 流中使用指定编码下数据,用转换流。
编码问题其实很简单,永远使用同一种编码即可。
FileReader=FileInputStream+GBK
FileWriter=FileOutputStream+GBK
//写入的时候用的字符流的UTF-8 编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"), "UTF-8");
// 指定编码UTF-8
osw.write("中国");
osw.close();
//那么读出的时候如果用字符流也应该用UTF-8 编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"osw.txt"), "UTF-8");
char[] chs = new char[1024];
int len = isr.read(chs);
String str = new String(chs, 0, len);
System.out.println(str);
打印流
PrintStream:字节打印流
PrintWriter:字符打印流
打印流特点:
A:可以写入任意类型的数据。
B:可以自动刷新。必须先启动并且是使用println,printf 及format 方法才有效。
C:可以直接对文件进行写入。
哪些流对象是可以直接对文件进行操作的?
看构造方法, 是否有同时接受File 和String 类型的参数构造。
注意: 打印流只有写数据的,没有读取数据的。
案例: 用打印流复制文本文件
// 封装数据源
BufferedReader br = new BufferedReader(new FileReader(
"PrintWriterDemo.java"));
// 封装目的地
PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true);
String line = null;
while((line=br.readLine())!=null){
pw.println(line);
}
pw.close();
br.close();
注意:
A:读取文件的时候,如果是文件夹,会出现:FileNotFoundException: test (拒绝访问。)
B:写文件的时候,如果没有后缀名,它也会自动生成一个文件 而这个种类型的文件通过记事本类型的软件是可以打开的。
序列化流
序列化:把对象按照流一样的方式传输或者存储。
ObjectOutputStream 将Java 对象的基本数据类型和图形写入OutputStream 。
void writeObject(Object obj)
反序列化:把网络中的流数据或者文件中的流数据还原成对象。
ObjectInputStream:ObjectInputStream 对以前使用ObjectOutputStream 写入的基本数据和对象进行反序列化
Object readObject()
注意问题:
A:如果类的对象想被序列化流操作,请实现序列化接口。
B:看到了类实现了Serializable 接口,如果想解决黄色警告线请点击鼠标。
java.io.NotSerializableException 没有实现序列化接口异常
类通过实现java.io.Serializable 接口以启用其序列化功能。
该接口被称为序列化接口,是一个标记接口。没有任何功能需要实现。
类一旦实现了该接口,那么该类的对象就可以被序列化流进行操作。
Properties
Properties:是一个表示属性集的集合。可以从流中加载数据或者把数据保存到流中。键和值都是字符串。是唯一一个可以和IO 流结合使用的集合类。
Properties 的父亲是Hashtable,所以知道它是一个Map 体现的。那么就存储数据并遍历。
Properties 作为集合的特殊功能:
1: 修改功能
public Object setProperty(String key,String value)
2: 获取功能
public String getProperty(String key)
public String getProperty(String key,String defaultValue)
public Set<String> stringPropertyNames()
System 类的一个方法: public static Properties getProperties():系统属性
Properties 作为和IO 流结合使用的集合的特殊功能:
public void list(PrintStream out): 把集合中的数据按照键值对的形式存储到文本文
件中。
public void list(PrintWriter out): 把集合中的数据按照键值对的形式存储到文本文件
中。
public void load(InputStream inStream): 从文本文件中把数据加载到集合中。
public void load(Reader reader): 从文本文件中把数据加载到集合中。
注意: 对文本文件是有要求的, 要求数据必须是键值对形式。
public void store(OutputStream out,String comments): 把集合中的数据保存到文本
文件中。
public void store(Writer writer,String comments): 把集合中的数据保存到文本文件
中。
注意:store 和list 方法的区别list 的参数值能是PrintWriter 或PrintStream
而store 的参数是PrintStream 或者Writer
综合案例: 我有一个学生类,这个类包含一下成员变量:姓名,语文成绩,数学成绩,英语成绩。
请从键盘录入5 个学生信息,然后按照自己定义的格式存储到文本文件中;要求被存储的学生按照分数从高到低排序。
// 写一个学生类,有4 个成员变量。
System.out.println("学生信息录入开始");
// 需要用到排序,定义TreeSet 集合
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要条件
int num = s2.getSum() - s1.getSum();
// 分析次要条件
// 当总分相同,还得继续比较每一门的分数是否相同
int num2 = (num == 0) ? s1.getChinese() - s2.getChinese() : num;
int num3 = (num2 == 0) ? s1.getMath() - s2.getMath() : num2;
// 当语文,数学,英语成绩都相同的还得继续判断姓名是否相同。
int num4 = (num3 == 0) ? s1.getName().compareTo(s2.getName())
: num3;
return num4;
}
});
for (int x = 0; x < 5; x++) {
// 用Scanner 实现键盘录入。
Scanner sc = new Scanner(System.in);
// 键盘录入数据
System.out.println("请输入第" + (x + 1) + "个学生的姓名:");
String name = sc.nextLine();
System.out.println("请输入第" + (x + 1) + "个学生的语文成绩:");
int chinese = sc.nextInt();
System.out.println("请输入第" + (x + 1) + "个学生的数学成绩:");
int math = sc.nextInt();
System.out.println("请输入第" + (x + 1) + "个学生的英语成绩:");
int english = sc.nextInt();
// 把数据封装到学生对象中
Student s = new Student();
s.setName(name);
s.setChinese(chinese);
s.setMath(math);
s.setEnglish(english);
ts.add(s);
}
// 遍历集合,获取到集合中的每一个数据,用输出流写到文本文件。
BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));
bw.write("姓名\t 语文\t 数学\t 英语");
bw.newLine();
bw.flush();
for (Student s : ts) {
StringBuilder sb = new StringBuilder();
sb.append(s.getName()).append("\t").append(s.getChinese()).append("\t").append(s.getMath()).append("\t").append(s.getEnglish());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
bw.close();
System.out.println("学生信息录入成功");
part23 多线程
多线程:应用程序有多条执行路径。
进程:正在运行的应用程序。
线程:一条路径,进行的执行单元。
注意:线程是依赖于进程,而进程是操作系统直接创建的。
Java 语言是不能直接调用操作系统的属性的。C 语言可以。
为什么要使用多线程?什么时候使用?为了提高效率。
当要操作的代码比较多(耗时),循环次数比较多的时候就可以使用多线程。
多线程怎么实现呢?
方式1:继承Thread 类。
A: 创建一个类(MyThread),继承Thread 类。
B: 重写Thread 类中的run()方法。
C: 启动并执行线程。
注意:这里是不能直接调用run()方法,需要调用start()方法。start()方法做了两件事:
A:启动线程。
B:自动调用run()方法。
同一个线程对象start()两次,会报一个异常:IllegalThreadStateException(线程状态异常。)
Thread 类的两个方法:
public final String getName(); 获取线程名称(Thread-编号, 编号是从0 开始)
public final void setName(String name); 设置线程名称。
public static void sleep(long mills); 让当天线程睡一段时间(根据传过来的毫秒值)
线程执行的随机性的原理:由于CPU 在做着高效的切换。程序的执行,其实就是在抢CPU 资源。
方式2:实现Runnable 接口。
A: 创建一个类(MyRunnable)实现Runnable 接口。
B: 重写run()方法。
C: 创建类(MyRunnable)的实例。
D: 把类(MyRunnable)的实例,做为Thread 类的构造参数传递。
注意事项:
因为MyRunnable 这个类是实现了Runnable 接口,所以在类中不能直接使用Thread 类的getName()这个方法。
怎么用呢?
public static Thread currentThread(); 返回正在执行的线程的引用(Thread.currentThread().getName())
既然有了第一种实现方式,为什么要有第二种实现方式?
A:避免了单继承的局限性。
B:实现Runnable 接口的方式,只创建了一个资源对象,更好的实现了数据(my)和操作(start())的分离。
开发中常用:实现Runnable 接口的方式。
多线程的生命周期图:
A: 新建(创建一个线程对象)
B: 就绪(具备执行资格, 不具备执行权)
C: 有可能发生阻塞(不具备执行资格和执行权)
sleep(),wait()
notify()
D: 运行(具备执行资格和执行权)
E: 死亡(线程对象变为垃圾, 等待垃圾回收器回收。)
多线程模拟买票出现了负数和重复值? 产生原因是什么? 怎么解决呢?
产生负数:
public class TicketRunnable implements Runnable {
public int tickets = 200;
@Override
public void run() {
while (true) {
//t1,t2,t3,t4 都进来了
//最后一次tickets 的值是1
if (tickets > 0) {
/*
* t1 满足, 进来了,
* t2 进来了,
* t3,
* t4 都进来了
* */
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* t1 醒了, 抢到了资源, 打印: 第一张票,完了以后, tickets 的值变成了0
* t2 醒了, 抢到了资源, 打印: 第0 张票, 完了以后, tickets 的值变成了-
1
* t3 醒了, 抢到了资源, 打印: 第-1 张票, 完了以后, tickets 的值变成了-
2
* t4 醒了, 抢到了资源, 打印: 第-2 张票, 完了以后, tickets 的值变成了-
3
* */
System.out.println(Thread.currentThread().getName() + "正在出售第"
+ (tickets--) + "张票");
}
}
}
}
产生重复值:
关键点:ticket--(ticket = ticket - 1)
A:获取ticket 的值。
B:修改ticke 的值。
C:把修改后的值,重新赋值给ticket 。
当步骤A 执行完后,还没来得及执行B,这个时候别的线程抢到了资源,打印的就是重复值。
产生原因:
由于线程的随机性和延迟性,导致线程访问共享数据出现了问题。
解决方案:找到可能出问题的代码,然后把可能出问题的代码用锁锁起来。
A:如何找可能出问题的代码?
1、是否有共享数据。
2、是否有多条语句操作共享数据。
3、是否在多线程环境中。
这三点也是多线程产生问题的原因。
B:怎么锁?
可以采用同步代码块的方式锁。
synchronized (锁对象)
{
要被锁的代码。
}
注意:
1、锁对象可以是任意对象。
2、多个线程的锁对象必须是同一个。不然可能会出现锁不住的情况。
锁的状态:开,关。
不同同步机制的锁对象分别是什么?
同步代码块:可以是任意类型。
同步方法:把synchronized 定义在方法的声明上。(写在方法的返回值的数据类型之前)
public synchronized void show();
this 。
静态方式:
当前类的字节码文件对象。
类名.class
以后使用同步代码块还是同步方法?
看需求,但是同步的代码越少越好,所以一般使用同步代码块。
如果一个方法中所有的代码都被加锁了,那么可以考虑使用同步方法。
线程间的通信问题:
线程通信:不同种类的线程间对共享数据的操作问题。
用学生类的案例来演示线程通信;
学生类: Student (资源类)
设置值: SetStudent (一个共享数据, 实现了Runnable 接口)
获取值: GetStudent(一个共享数据, 实现了Runnable 接口)
测试类:
正常的逻辑:
针对输出:( GetStudent)
判断是否有数据, 如果有就输出数据, 没有的话, 就等待设置。
(喝水: 判断水杯是否有水, 如果有就喝, 如果没有, 就等待小蜜去接水)
针对设置; (SetStudent)
判断是否有数据, 如果有就等待输出, 如果没有, 就设置。
(接水: 判断水杯是否有水, 如果有等待喝, 如果没有, 就接水。)
定义了一个标记: true 代表有数据, false 代表没有数据。
面试题: wait()方法和sleep()这个方法有什么区别?
wait(): Object 类下的方法, 不需要传递参数。释放锁对象, 释放资源。
sleep(): Thread 类, 需要传递参数, 不释放锁对象。
等待唤醒机制的原理:
Object 类中的两个方法:
wait(): 让当前线程处于等待状态。
notify(): 唤醒等待的线程。
线程的优先级;
public final void setPriority(int newPriority); 设置线程的优先级
public final int getPriority(); 获取线程的优先级
线程默认的优先级是5, 范围是1-10.
注意:
线程的优先级越高, 并不代表该线程一定第一个执行。
线程优先级可以再一定程度上, 让该线程获取较多的执行机会。
线程的拓展:
暂停线程:
public static void yield(); 暂停当前正在执行的线程对象, 并执行其他线程。
什么时候用?
他可以让线程更和谐一点的运行, 避免出现成片数据的情况。
注意: 如果想要真正的实现数据依次输出, 还得使用等待唤醒机制。
加入线程:
public final void join(); 等待该线程终止。
什么时候用?
当某个线程(A)需要在某个线程(B)执行结束后才执行, 就可以使用“加入线
程” 。
例子: 当线程B 执行完后才能执行线程A,
守护线程:
public final void setDaemon(boolean on); 设置线程为守护线程, 一旦前台线程(主
线程)结束了, 守护线程紧跟着就结束了。
main 方法也是一个线程。
part24 网络编程
网络编程概述
计算机网络:
概念:地理位置不同的多台计算机, 网络线路连接。网络管理软件, 网络协议,实现资源共享和信息传递
分类: 局域网,城域网,广域网,万维网
网络编程:用来实现网络互联的不同计算机运行的程序间数据交换
网络模型:网络之间使用何种规则进行通信
osi 七层参考模型
物理层,定义物理设备,传输比特流
数据链路层,mac 地址的封装与解封装(交换机)
网络层,ip 地址的封装与解封装(路由器), 数据包
传输层,定义传输协议和端口号(tcp udp)
会话层,发起会话或者接受会话请求
表示层,解释加密解密压缩解压缩(完成翻译)
应用层,终端应用,直接使用的软件,面向用户
tcp/ip 模型
主机到网络层--物理层, 链路层
网际层--网络层
传输层--传输层
应用层--会话层, 表示层, 应用层
网络通信三要素
网络通信(Socket 通信, 套接字编程)
实现网络互连的不同计算机上运行的程序间可以进行信息交换
即用java 语言实现不同计算机间的通信
三要素:
IP 地址:Ip 是网络中每一台计算机的唯一标识
端口:用于标识进程的逻辑地址,不同的进程(应用程序)拥有不同的端口
协议:定义通信规则--udp 和tcp 协议
IP 地址
概念:网络中的计算机的唯一标识
表示形式:点分十进制计数法--192.168.0.100
二进制对应的十进制
二进制太长不方便记忆
每段(8 位)范围0~255
ip 地址分类
A 类1.0.0.1-127.255.255.254(10.x.x.x 是私有地址)
B 类128.0.0.1--191.255.255.254(172.16.0.0--172.31.255.255 为私有)
C 类192.0.0.1--223.255.255.254
D 类224.0.0.1--223.255.255.254
E 类240.0.0.1--247.55.255.254
ip 地址组成
网络号码+主机地址
A 类第1 段为网络号码, 后3 个是本地主机的地址: 256^3 个主机(广域网)
B 类前2 段为网络号码, 后2 个是本地主机的地址: 256^2 个主机(校园网)
C 类前3 段为网络号码, 后1 个是本地主机的地址: 256 个主机(局域网)
查看本机ip: win+r-->cmd-->ipconfig /all
查看网络是否有问题: ping+ip 地址
ping:127.0.0.1 本机回环地址: 检查本机环境是否有问题
ping:x.x.x.x 别人地址检查外部环境是否有问题
ping:x.x.x.x -t 向。。一直发包
端口号:
每个网络进程至少有一个逻辑端口
用于标识进程的逻辑地址, 不同进程标识不一样
有效端口: 0~65535(255^2).其中0~1024 是系统使用或者保留端口
**协议: 定义的通信规则
udp 协议
数据打包(将数据源和目的地封装成数据包)
数据有限制(数据包限制在64k)
面向无连接(不需要建立连接)
不可靠协议
速度快
举例: QQ 群聊, 短信
tcp 协议: 三次握手协议--请求, 回应, 发送
建立连接通道
数据没有限制
面向连接的协议(三次握手)
可靠
速度慢
举例: 蓝牙, QQ 单聊, 打电话
用什么: 看需求
Socket 编程
是为网络编程提供一种机制, 包装了端口和ip 地址
特点:
数据两端都独有Socket
网络通信实际就是Socket 通信
数据在两个Socket 间通过IO 传输
Socket 通信--套接字编程--网络编程
InetAddress 类
ip 地址的包装类, 该类的构造方法是私有的,
怎么该类的对象:
InetAddress getByName(String host),根据主机名返回对应的ip 地址(对象
形式)
注意: 参数可以是主机名也可以是ip 地址
成员方法:
getHostAddress();返回ip 地址(字符串)
getHostName();返回主机名
udp 发送步骤
创建发送端Socket 发送对象
DatagramSocket 类的无参构造
创建数据并把数据打包
DatagramPacket(byte[] bys,length,InetAddress ip,port(端口号))
发送数据
send(DatagramPacket dp)
释放资源
ds.close();
udp 接收步骤
创建接受端Socket 对象
DatagramSocket(int port)
创建数据包(接收容器)
DatagramPack(byte[] bys,int length)
调用接收方法
receive(dp)
*解析数据包, 把数据显示在控制台, 从包里拿到需要的对象
从数据包中获得ip(字符串ip)
InetAddress getAddress()
InetAddress getHostAddress()
从数据包中获得客户端发的数据
byte[] getData();
int getLength();//获取实际长度
释放
ds.close();
注意:
发送接收的端口一定要一致
一个端口不可以被多个程序使用
案例: 聊天室(掌握)
Scoket 类
Tcp 协议客户端的步骤
创建客户端Socket 对象
Socket(host,port) host 可以是ip 地址
建立连接
获取输出流, 写数据即可, 往服务器发送数据
OutputStream getOutputStream();
释放资源
tcp 协议服务器端步骤
创建服务器Socket 对象
ServerSocket(int port)
监听连接
public Socket accept();监听并接收到此套接字的连接
获取输入流, 读取数据并显示
public InputStream getInputStream()
释放
注意:
必须先开服务器端, 然后再开启客户端, 不然程序会出错
键盘录入数据写入文本文件
数据写进去了, 但服务器反馈没有成功
原因:
part25 正则反射
正则表达式:
概述:就是符合某种规则的字符串。
需求:
判断是否是QQ 号码。(5-15 位数字,不能以0 开头)
[1-9][0-9]{4,14}
规则字符: Pattern 类
A:字符
n 字符n 本身出现一次
\\ 在正则中,两个\表示一个\
\r 回车
\n 换行
B:字符类
[abc] a,b,c 任意一个字符出现一次
[^abc] 任意字符,a,b,c 除外
[a-zA-Z] 所有的英文字母一次
[0-9]任意数字一次
C:预定义字符类
. 单独的一个点表示任意字符一次
\d 任意数字一次, 相当于[0-9]
\w 单词字符(字母, 数字, _),相当于[a-zA-Z_0-9]
D:边界匹配器
^ 行的开头
$ 行的结尾
\b 这里出现的不能是单词字符
E:数量词
n? 字符n 一次或一次都没有
n* 字符n 零次或者多次
n+ 字符n 一次或者多次(至少一次)
n{a} 字符n 恰好出现a 次
n{a,} 字符n 至少出现a 次
n{a,b} 字符n 至少出现a 次, 不超过b 次
基本功能:
判断功能:
public boolean matches(String regex); 判断该字符串是否与给定的正则表达式匹配。
切割功能:
public String[] split(String regex); 按照给定的正则切割该字符串
替换功能:
public String replaceAll(String regex, String replacement);
用指定的字符串来替换字符串中所有符合正则规则的字符串。
regex:正则,用来检索要替换的字符串
replacement:用来替换的字符串。
获取功能:
使用的是模式对象Patter 和匹配器Matcher 对象。
Matcher 类下的两个方法:
public boolean find();尝试查找与该模式匹配的输入序列的下一个子序列。
理解:就是大串中查找小串,看是否有符合规则的小串。
public String group();
返回由以前匹配操作所匹配的输入子序列。
理解:就是返回刚才查找到的,符合规则的小串。
A: 通过字符输入流来读取文本文件。
B: 对读到的每一行数据进行校验。
C: 如果数据符合需求, 就把该数据存到集合中。
D: 遍历集合。
反射:
概述:在运行期间,可以通过Class 文件对象(字节码文件对象)来使用构造方法,成员变量,成员方法。
怎么获取Class 文件对象:
A:Object 类中的getClass()方法。
B:数据类型的静态的class 属性(类名.class)
C:Class 类中的forName(String className); 注意;className 的名字要是带全路径的。
开发中常用第三种,因为它可以结合配置文件使用。
注意:一个类可以有多个对象,但是只能有一个Class 文件对象。
part26 设计模式
概述:把相似的东西抽取出来的模型
分类
创建型模式:创建对象。--工厂模式,单例模式
结构型模式:类与类的关系(研究对象间的关系)--装饰模式
行为型模式:对象能够做什么。--模版模式
GOF 设计模式(23 种)
人:闫闳(国内研究设计模式较早的)
创建型模式:
工厂模式
简单工厂模式
Animal
Dog
Cat
Animal
工厂方法模式
原理
首先我们先写一个动物的抽象工厂类, ()
当我们需要一个新对象的时候, 按照如下操作
写一个该该类的实体类去继承动物类
写一个该类的工厂类去继承动物类
然后在该类的工厂类中创建该类对象
Animal
Dog
Cat
Pig
AnimalFactory
DogFactory extends AnimalFactory
CatFactory extends AnimalFactory
PigFactory extends AnimalFactory
测试类
单例模式:
类在内存中只存在一个对象--如网站访问统计、windows 打印服务
应用: 线程池, 数据库连接池
面试题: 写出一个单例设计模式
分析: 类在内存中只存在一个对象
外界不能随意创建对象
把构造方法私有
类本身要创建一个对象
静态方法只能访问静态, 对象要加静态
为了不让外界通过类名直接访问就加私有
通过公共的方式提供给别人: public 修饰的方法
为了让外界能够直接通过类名访问该方法, 需要对方法加静态
饿汉式: (开发中用)
类一加载就创建对象
public Student {
private Student(){}
//类一加载就创建对象
private stattic Student s = new Student();
public static Student getStudent(){
return s;
}
}
Student s = Student.getStudent();
懒汉式:(面试中用):什么时候用就什么时候创建对象
jdk 中的单例模式:RunTome 类
public Student {
private Student(){}
//什么时候用就什么时候创建对象
//面试时别忘加锁
private synchronized stattic Student s = null;
public static Student getStudent(){
if(s==null){
s = new Student();
}
return s;
}
}
为什么懒汉式: (面试中用)
懒汉式是延迟加载: 什么时候用, 什么时候创建对象
懒汉式有线程安全问题: 方法上加锁
装饰模式: 一种是通过继承实现, 一种是通过实现接口实现
对类原有的功能进行修饰和包装扩展
实现步骤:
找到装饰的抽象事物Phone
创建一个实体类(PhoneImple)只有打电话功能, 来实现或者继承第一步
的抽象事物(Phone 接口)
创建一个装饰类(PhoneDecorate), 来实现Phone 接口, 调用实体类对
象
装饰类子类继承装饰类, 重写装饰类的方法, 实现功能扩充
Phone 接口
PhoneImpl 具体实现类
PhoneDecorate 抽象类
ColorPhoneDecorate 具体装饰类
GuangGaoPhoneDecorate 具体装饰类
模板方法模式
最优体现是以抽象类的形式体现的
打印模板类
打印方法: 具体的
三个抽象方法
具体实现类1
具体实现类2
需求: 模仿刚才的代码, 用模板方法模式设计一个计算, 程序运行时间
的模板类
long start = System.currentTimeMillis();
code()
long end = System.currentTimeMillis();
JAVASE笔记回顾的更多相关文章
- grasp设计模式笔记回顾
根据讲师所讲做了一下笔记以便自己能方便学习: ------------------------------------------grasp设计模式: grasp(general responsibi ...
- javaSE 笔记一
java 环境变量配置 步骤: 右键[计算机]图标 –>[属性]–>[高级系统设置]–>[环境变量] 在"系统变量"里找到"Path" ...
- Javase部分回顾(static (静态修饰符),修饰方法,单利的设计模式, 封装)
static (静态修饰符) 1.修饰成员变量 静态变量的访问方式: 方式一 : 通过对象访问. 对象.变量名 ...
- 最全C语言笔记回顾
- javase基础回顾(一)ArrayList深入解析 解读ArrayList源代码(JDK1.8.0_92)
我们在学习这一块内容时需要注意的一个问题是 集合中存放的依然是对象的引用而不是对象本身. List接口扩展了Collection并声明存储一系列元素的类集的特性.使用一个基于零的下标,元素可以通过它们 ...
- javase基础回顾(二)LinkedList需要注意的知识点 阅读源码收获
我们在学习这一块内容时需要注意的一个问题是 集合中存放的依然是对象的引用而不是对象本身. List接口扩展了Collection并声明存储一系列元素的类集的特性.使用一个基于零的下标,元素可以通过它们 ...
- javase基础回顾(四) 自定义注解与反射
本篇文章将从元注解.自定义注解的格式.自定义注解与反射结合的简单范例.以及自定义注解的应用来说一说java中的自定义注解. 一.元注解 元注解也就是注解其他注解(自定义注解)的java原生的注解,Ja ...
- JavaSE笔记-泛型
定义带泛型的类 public class Cat<T> { //可以用T定义实例变量 private T name; //可以用T定义形参 //构造器没有<> public C ...
- JavaSE笔记-异常
Java 异常 Throwable类的体系结构(一些常用的) 异常分类 checked,unchecked 区分:RuntimeException及其子类,Error类及其子类,是unchecked ...
随机推荐
- 解决Cannot change version of project facet Dynamic Web M
dynamic web module 版本之间的区别: Servlet 3.0 December 2009 JavaEE 6, JavaSE 6 Pluggability, Ease of devel ...
- Scala underscore的用途
_ 的用途 // import all import scala.io._ // import all, but hide Codec import scala.io.{Codec => _, ...
- mysql ALL_O_DIRECT引发的unaligned AIO/DIO导致hang
公司内部有一套mysql环境,使用的是percona server分支(和其他几十套环境的版本.参数完全相同),就这套环境每隔两三天就会hang一次,关键hang的时候服务器cpu也就是百分之三四十, ...
- 从" ThinkPHP 开发规范 "看 PHP 的命名规范和开发建议
稍稍水一篇博客,摘抄自Think PHP 的开发规范,很有引导性,我们可以将这些规范实践到原生 PHP 中. 命名规范 使用ThinkPHP开发的过程中应该尽量遵循下列命名规范: 类文件都是以.cla ...
- NullPointerException at android.widget.AbsListView.obtainView at android.widget.ListView.makeAndAddView
使用ExpandableListView的时候,报如下错.网上搜索发现原来是在CommonNumberQueryAdapter的getGroupView()方法里返回的是null,注意细节哦!!! 1 ...
- C# DevExpress 的gridControl或gridView数据导出失败解决方法
来自:http://blog.csdn.net/lybwwp/article/details/8049464 谢谢 在使用DevExpress 的GridPanel控件的时候出现了一个莫名其妙的现象, ...
- 实验12:Problem F: 求平均年龄
Home Web Board ProblemSet Standing Status Statistics Problem F: 求平均年龄 Problem F: 求平均年龄 Time Limit: ...
- Bit-Coin收入的一分钱
好吧,这是我在Slush's pool上对Bit-coin收入的第一分钱. 回想起来,2013年平安夜开始到今天,将近3个月没日没夜窝在这个矿里挖矿 从最开始的集成显卡挖,买了显卡挖,加了显卡挖,使用 ...
- iOS开发笔记11:表单键盘遮挡、浮点数价格格式化显示、省市区选择器、View Debugging
1.表单键盘遮挡 应用场景为一个collectionView上有多个textfield.textView供用户填写信息. 之前输入项较少时,采取的方法比较粗暴,didSelectItemAtIndex ...
- OC语言-04-OC语言-核心语法
一.点语法 1> 基本使用 点语法本质上是set方法/get方法的调用 2> 使用注意 若出现在赋值操作符的右边,在执行时会转换成get方法 若出现在赋值操作符的左边,在执行时会转换成se ...