Java基础总结
public class test {
public static void main(String[] args){
String s = "aaaabbcaadgg";
StringBuffer sb = new StringBuffer();
sb.append(s);
int[] array = new int[s.length()];
for(int i =0; i < array.length; i++){
array[i] = 0;
}
for(int i =0; i < sb.length(); i++){
for(int j = i+1; j < sb.length(); j++){ //从i+1开始比较
if(sb.charAt(i) == sb.charAt(j)){
sb.delete(j, j+1); //删除第j个节点
array[i]++; //统计次数
j--;//因为j会自动加1,所以j要-1
}
}
array[i] = array[i]+1;
}
for(int i= 0; array[i] != 0; i++){
System.out.println(array[i]);
}
}
}
泛型
- 泛型的好处
- 把运行期间的问题提前道理编译时。
- 避免了无谓的强制类型转换。 - 泛型在集合中的应用的注意事项:
-泛型中没有多态的概念,两边的数据必须要一致,或者只写一边的。
public class Demo1{
public static void main(String[] args){
ArrayList<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add(123);//错误,添加了字符串类型的数据
//把集合中的所有元素转换成大写
for(int i = 0; i < list.size(); i++){
String str = list.get(i);
System.out.println(str.toUpperCase());
}
}
}
自定义泛型
- 可以理解成一个数据类型的占位符,或者理解为一个数据类型的变量。
泛型方法的定义
修饰符 <声明自定义泛型> 返回值类型 函数名(形参…){}
- 注意事项:
- 1.在方法上定义的泛型是传入实参的时候确定的。
- 2.自定义泛型的使用需要符合标识符的命名规则。
- 注意事项:
//一个函数可以接受任意类型的参数,要求参数的返回值与实参的类型一致
public static <T> T abc(T o){
return o;
}
- 泛型类
- 泛型类的定义格式:
class 类名<声明自定义的泛型>{
}
- 注意事项:
- 在类上自定义的泛型的具体数据类型是在创建对象的时候指定的。
- 在类上自定义类泛型,如果创建该类的时候没有指定泛型的具体类型,那么默认是OBject类型。
class Worker implements Comparator<Worker>{
//实现Comparator接口中的compare方法
public int compare(Worker o1, Workor o2){
return 0;
}
}
//自定义集合对象的事项
class MyList<T> {
//定义一个数组
Object[] arr = new Object[10];
public MyList(){}
int index = 0;
public void add(T o){
arr[index++] = o;
}
}
public class Demo2{
public static void main(String[] args){
MyList<String> list = new MyList<String>();
list.add("adc");
}
}
泛型接口
- 泛型接口的定义格式:
interface 接口名<声明自定义的泛型>{
}
- 在接口上自定义泛型的具体数据类型是在实现给接口的时候指定的。如果一个接口自定义了泛型,那么实现该接口的时候默认的数据类型是Object
- 泛型接口的定义格式:
interface Dao<T>{
public void add(T t);
public T remove();
}
public class Demo4 implements Dao<String>{
public static void main(String[] args) {
new Demo4();
}
@Override
public void add(String t) {
// TODO Auto-generated method stub
}
@Override
public String remove() {
// TODO Auto-generated method stub
return null;
}
}
内省
反射的用法:
public class Demo1 { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, NoSuchFieldException, IOException { Person p = (Person)getPerson(); System.out.println(p); } private static Object getPerson() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, NoSuchFieldException { //获取资源路径 BufferedReader br = new BufferedReader(new FileReader("obj.txt")); String addressName = br.readLine(); //得到Class对象 Class clazz = Class.forName(addressName); //通过Class对象创建对象 Object o = clazz.newInstance(); //通过Class对象获无参数构造方法 Constructor constructor = clazz.getConstructor(null); String line = null; while((line = br.readLine())!=null){ String[] datas = line.split("="); //将建和值分开 //得到Field对象 Field field = clazz.getDeclaredField(datas[0]);//通过属性的名字获取字段的类型 if(field.getType() == int.class) //判断字段的类型 { //设置字段的值 field.setAccessible(true); field.set(o, Integer.parseInt(datas[1])); }else{ field.setAccessible(true); field.set(o, datas[1]); } } return o; } }
- 内省
public class Demo2 {
@Test
public void getAllProperty() throws IntrospectionException{
//Introspector 内省类
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
//通过BeanInfo获取所有的属性描述其
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors(); //获取一个类中的所有属性描述器
for(PropertyDescriptor p : descriptors){
System.out.println(p.getReadMethod()); //get方法
}
}
//@Test
public void testProperty() throws Exception{
Person p = new Person();
//属性描述器
PropertyDescriptor descriptor = new PropertyDescriptor("id", Person.class);
//获取属性对应的get或者是set方法设置或者获取属性了。
Method m = descriptor.getWriteMethod(); //获取属性的set方法。
//执行该方法设置属性值
m.invoke(p,110);
Method readMethod = descriptor.getReadMethod(); //是获取属性的get方法
System.out.println(readMethod.invoke(p, null));
}
}
- BeanUtils:
BeanUtils主要解决 的问题: 把对象的属性数据封装 到对象中。
BeanUtils的好处:
- BeanUtils设置属性值的时候,如果属性是基本数据 类型,BeanUtils会自动帮我转换数据类型。
- BeanUtils设置属性值的时候底层也是依赖于get或者Set方法设置以及获取属性值的。
- BeanUtils设置属性值,如果设置的属性是其他的引用 类型数据,那么这时候必须要注册一个类型转换器。
BeanUtilss使用的步骤:
1. 导包commons-logging.jar 、 commons-beanutils-1.8.0.jar
public class Demo3 {
public static void main(String[] args) throws Exception {
//从文件中读取到的数据都是字符串的数据,或者是表单提交的数据获取到的时候也是字符串的数据。
String id ="110";
String name="陈其";
String salary = "1000.0";
String birthday = "2013-12-10";
//注册一个类型转换器
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class type, Object value) { // type : 目前所遇到的数据类型。 value :目前参数的值。
Date date = null;
try{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = dateFormat.parse((String)value);
}catch(Exception e){
e.printStackTrace();
}
return date;
}
}, Date.class);
Emp e = new Emp();
BeanUtils.setProperty(e, "id", id);
BeanUtils.setProperty(e, "name",name);
BeanUtils.setProperty(e, "salary",salary);
BeanUtils.setProperty(e, "birthday",birthday);
System.out.println(e);
}
}
IO流
IO解决问题: 解决设备与设备之间 的数据传输问题。 比如: 硬盘—>内存 内存—–>硬盘
字节流:
输入字节流:
———| InputStream 所有输入字节流的基类。 抽象类。
————| FileInputStream 读取文件的输入字节流。
————| BufferedInputStream 缓冲输入字节流。 该类内部其实就是维护了一个8kb字节数组而已。 该类出现的目的是为了提高读取文件数据的效率。
输出字节流:
———| OutputStream 所有输出字节流的基类。 抽象类。
————| FileOutputStream 向文件输出数据 的输出字节流。
————| BufferedOutputStream 缓冲输出字节流。 该类出现的目的是为了提高向文件写数据的效率。 该类内部其实也是维护了一个8kb的字节数组而已。
什么情况使用字节流: 读取到数据不需要经过编码或者解码的情况情况下这时候使用字节流。比如:图片数据
字符流 = 字节流 + 编码(解码)
字符流:
输入字符流
——–| Reader 所有输入字符流的基类。 抽象类。
———–| FileReader 读取文件字符的输入字符流。
———–| BufferedReader 缓冲输入字符流。 该类出现的目的是为了提高读取文件字符的效率并且拓展了功能(readLine()),它内部 其实就是维护了一个8192个长度的字符数组。
输出字符流
——-| Writer 所有输出字符流的基类。 抽象类。
————| FileWriter 向文件输出字符数据的输出字符流。
—————| BufferedWriter 缓冲输出字符流。该类出现的目的是为了提高写文件字符的效率并且拓展了功能(newLine())。
什么情况下使用字符流:如果读写的都是字符数据,这时候我们就使用字符流。
转换流:
输入字节流的转换流 输入字节流———输入字符流
InputSrteamReader
输出字节流的转换流
OutputStreamWriter
转换流的作用:
1. 可以把对应的字节流转换成字符流使用。
2. 可以指定码表进行读写文件的数据。
FileReader, FileWriter这两个类默认是使用的是gbk编码 表。不能由你来指定码表读写文件数据。
public class Demo1 {
public static void main(String[] args) throws Exception {
// testInput();
// writeFile();
readFile();
}
public static void readFile() throws IOException{
//建立文件与程序的输入数据通道
FileInputStream fileInputStream = new FileInputStream("F:\\a.txt");
//创建输入字节流的转换流并且指定码表进行读取
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
int content = 0;
while((content = inputStreamReader.read())!=-1){
System.out.println((char)content);
}
//关闭资源
inputStreamReader.close();
/*FileReader fileReader = new FileReader("F:\\a.txt"); //默认使用的是gbk码表
int content = 0;
while((content = fileReader.read())!=-1){
System.out.print((char)content);
}
//关闭资源
fileReader.close();*/
}
//指定使用utf-8码表把数据写出到文件上。
public static void writeFile() throws IOException{
//建立了文件与程序的数据 通道
FileOutputStream fileOutputStream = new FileOutputStream("F:\\a.txt");
//创建一个输出字节流的转换流并且指定码表进行写数据
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"utf-8");
outputStreamWriter.write("大家好"); //中文在utf-8码表中占三个字节。
//关闭资源
outputStreamWriter.close();
}
public static void testOutput() throws Exception{
Socket socket = new Socket(InetAddress.getLocalHost(),9090);
//获取到socket的输出流对象。
OutputStream outputStream = socket.getOutputStream();
//把输出字节流转换成输出字符流
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
outputStreamWriter.write("不饿!");
}
public static void testInput() throws Exception{
InputStream in = System.in;
// int content = in.read(); // 每次只会读取到一个字节的数据
//需要把字节流转换成字符流使用。
InputStreamReader inputStreamReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
System.out.println(bufferedReader.readLine());
}
}
集合
集合: 存储对象数据 的集合容器。
单例集合
———-| Collection 单例集合 的根接口
—————-| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
——————-| ArrayList ArrayList底层是使用了Object数组实现 的。 特点: 查询速度快,增删慢。
——————-| LinkedList LinkedList底层是使用了链表数据结构实现的。特点: 查询速度慢,增删快
——————-| Vector 底层是使用了Object数组实现 的, 实现原理与ArrayList 是一致的,但是是线程安全的,操作效率低。
—————-| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
——————-| HashSet 底层是使用了哈希表实现 的。 特点: 存取速度快。
HashSet存储元素的原理:
往hashSet添加元素的时候,首先会调用元素的hashCode方法得到元素的哈希码值,然后把哈希码值经过运算算出该元素存在哈希表中的位置。
情况1:如果算出的位置目前还没有存在任何的元素,那么该元素可以直接添加到哈希表中。
情况2: 如果算出的位置目前已经存在其他的元素,那么还会调用元素 的equals方法再与这个位置上 的元素比较一次。
如果equals方法返回的是true,那么该元素被视为重复元素,不允许添加。如果equals方法返回 的是false,那么该元素也可以被添加。
——————| TreeSet 底层是使用了红黑树(二叉树)数据结构实现的。 特点: 对集合中的元素进行排序存储、。
TreeSet要注意的事项:
1. 往TreeSet添加元素 的时候,如果元素具备自然顺序的特点,那么TreeSet会根据元素 的自然顺序特性进行排序 存储。
2. 往TreeSet添加元素 的时候,如果元素不具备自然顺序的特点,那么元素所属的类就必须要实现Comparable接口,把比较的规则定义在CompareTo方法上。
3. 往TreeSet添加元素 的时候,如果元素不具备自然顺序的特点,那么元素所属的类就也没有实现Comparable接口,那么在创建TreeSet对象的时候必须要传入比较器对象。
比较器 的定义格式:
class 类名 implements Comparator{
}
双列集合
———-| Map 存储的数据都是以键值对的形式存在的,键可以不重复,值可重复。
————-| HashMap 底层也是使用了哈希表实现的。
————-| TreeMap 底层也是使用了红黑树数据结构实现的。
```java
class Person{
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public int hashCode() {
return this.id;
}
@Override
public boolean equals(Object obj) {
Person p = (Person)obj;
return this.id == p.id;
}
@Override
public String toString() {
return "编号:"+ this.id +" 姓名: "+ this.name;
}
}
public class Demo1 {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<Person>();
set.add(new Person(110,"狗娃"));
set.add(new Person(111,"狗"));
System.out.println("集合的元素:"+ set);
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Set;
public class Demo2 {
public static void main(String[] args) {
ArrayList<String> list =new ArrayList<String>();
//使用get方法遍历。
list.add("张三");
list.add("李四");
list.add("王五");
System.out.println("======get方式遍历=========");
for(int i = 0 ; i < list.size() ; i++){
System.out.print(list.get(i)+",");
}
//使用迭代器 注意: 迭代器在迭代的 过程中不能使用集合对象修改集合中的元素个数。如果需要修改要使用迭代器的方法进行修改,
System.out.println("\r\n======迭代器方式遍历=========");
HashSet<String> set = new HashSet<String>();
set.add("狗娃");
set.add("狗剩");
set.add("铁蛋");
/*Iterator<String> it = set.iterator(); //获取到迭代器
while(it.hasNext()){
System.out.print(it.next()+",");
}
*/
for(String item : set){
System.out.print(item+",");
}
System.out.println("\r\n======entrySet方式遍历=========");
HashMap<String, String> map = new HashMap<String, String>();
map.put("张三","001");
map.put("李四","002");
map.put("王五","003");
Set<Entry<String,String>> entrys = map.entrySet(); //
for (Entry<String,String> entry : entrys) {
System.out.println("键:"+entry.getKey()+" 值:"+entry.getValue());
}
}
}
多线程
创建方式:
方式一:继承Thread
1.自定义一个类继承Thread类
2.重写Thread的run方法,并且把自定义线程任务代码定义在run方法上。
3.创建Thread子类的对象,并且使用start()方法启动。方式二:实现Runnable接口
1.自定义一类实现实现Runnable接口
2.实现Runnable接口中的run方法,并且把自定义任务的代码定义在run()方法上。
3.创建Runable实现类的对象
4.创建Thread类的对象。并且把Runnale()实现类的对象作为参数传递。
5.调用Thread对象的start方法开启线程。
线程安全出现的解决方法
- 存在两个或者两个以上的线程共享着一个资源
- 操作共享资源的代码必须有两句或者两句以上。
- 同步代码块
synchronized(锁){
需要被同步的代码
}
- 同步函数
修饰符 synchronized 返回值类型 函数名(形参列表...){
}
- 注意事项
- 同步代码块的锁可以是任意对象。同步函数的锁是固定的。非静态函数的锁对象是this对象,静态函数的锁对象是class对象。
- 锁对象必须是多线程共享的对象
- 在同步代码块中调用sleep方法不会释放锁对象,如果调用了wait()方法就会释放锁对象。
单元测试框架
junit(单元测试框架)
目前存在的问题:
1. 目前的方法如果需要测试,都需要在main方法上调用。
2. 目前的结果都需要我们人工对比。
junit要注意的细节:
- 如果使用junit测试一个方法的时候,在junit窗口上显示绿条那么代表测试正确,
如果是出现了红条,则代表该方法测试出现了异常不通过。 - 如果点击方法名、 类名、包名、 工程名运行junit分别测试的是对应的方法,类、 包中 的所有类的test方法,工程中的所有test方法。
- @Test测试的方法不能是static修饰与不能带有形参。
- 如果测试一个方法的时候需要准备测试的环境或者是清理测试的环境,那么可以@Before、 @After 、@BeforeClass、 @AfterClass这四个注解。
@Before、 @After 是在每个测试方法测试的时候都会调用一次, @BeforeClass、 @AfterClass是在所有的测试方法测试之前与测试之后调用一次而已。
- 如果使用junit测试一个方法的时候,在junit窗口上显示绿条那么代表测试正确,
junit使用规范:
- 一个类如果需要测试,那么该类就应该对应着一个测试类,测试类的命名规范 : 被测试类的类名+ Test.
- 一个被测试的方法一般对应着一个测试的方法,测试的方法的命名规范是: test+ 被测试的方法的方法名。
public class Demo1 {
//@Test //注解
public void getMax(int a, int b){
/* int a = 3;
int b = 5 ;*/
int max = a>b?a:b;
System.out.println("最大值:"+max);
}
@Test
public void sort(){
int[] arr = {12,4,1,19};
for(int i = 0 ; i < arr.length-1 ; i++){
for(int j = i+1 ; j<arr.length ; j++){
if(arr[i]>arr[j]){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
System.out.println("数组的元素:"+Arrays.toString(arr));
}
}
public class Demo2 {
//准备测试的环境
//@Before
@BeforeClass
public static void beforeRead(){
System.out.println("准备测试环境成功...");
}
//读取文件数据,把把文件数据都
@Test
public void readFile() throws IOException{
FileInputStream fileInputStream = new FileInputStream("F:\\a.txt");
int content = fileInputStream.read();
System.out.println("内容:"+content);
}
@Test
public void sort(){
System.out.println("读取文件数据排序..");
}
//清理测试环境的方法
// @After
@AfterClass
public static void afterRead(){
System.out.println("清理测试环境..");
}
}