18-11-11:同类不同对象的方法指向一个区、成员变量与局部变量、私有化、构造方法及其重载.txt****
两个对象所指向的方法是同一个地址:
如果有两个对象p1,p2,他们的方法其实都是放在方法区中。
而他们的对于共同指向此方法
成员变量和局部变量区别:
位置:
成员变量是在类中声明的
局部变量是在方法体中或者形式参数中声明
内存:
成员变量是在堆中
局部变量是在栈中
初始化值:
成员变量因为是在堆中所以有初值
局部变量在栈中,所以声明后必须要先赋值才能使用
private修饰符:
放置位置:
放在变量或方法的最前面
作用:
被修饰后的变量或方法只可以在本类中使用,在外类不可见。
这样可以保证数据安全
配合:
被private修饰了的变量一定要有对应的setXxx() 和 getXxx()公有方法
构造方法:
格式:
public Student(...){ //与类名同名,且没有返回类型。
}
调用构造方法:
Student s = new Student(..) //其实new后面的就是调用了一个类的构造方法
构造方法的注意事项与重载:
如果没有构造方法,则系统会自动提供一个无参数的构造方法。
如果有了带参数的构造方法,无参构造方法就要自己构造。
推荐只要写一个类,就要有一个无参构造方法
18-11-12:方法的形参和返回值可以是对象、API、==详解、String对象初步、直接赋值和new字符串对象区别.txt****
类中的方法的形式参数和返回值可以是一个对象:
形参-例如:
public void UseStudent(Student s){
System.out.println("我是个老师,现在调用学生的方法");
s.speak();
}
返回值-例如:
public Student getStudent(){ //返回类型是类,则返回对象
Student s = new Student();
return s;
}
API的使用:
API就是帮助文档
==:
如果是基本数据类型则比较的是值是否相等。
如果是引用数据类型则比较的是地址是否相等。
String对象初步:
String是个特殊的引用类型对象
syso(str) //一般来说打印引用类型变量结果为其引用值,而打印字符串类型对象则直接打印结果
new出的字符串对象和直接赋值的字符串对象的区别比较:
new方式:
new出来的依然是在堆内存,但是字符串的内容在方法区的常量池中。
栈中的引用变量存了堆的地址,而堆中对象是存的常量池的地址。
直接赋值:
栈中的引用变量直接存的是常量池中的地址。
常量池:
字符串一般存在方法区当中的常量池中,同一个字符串在常量池中的位置唯一
举例1:
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1==s2); //false
原因分析:
s1存的是常量池当中的002;
s2存的是堆中的001,堆中的001在存的是常量池中的002;
001 != 002 所以false
举例2:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); //true
原因分析:
s1和s2存的都是常量池中的002,所以相等。
注意: 因为字符串对象也是引用数据,所以在进行==比较的是地址的值。
如果要比较字符串的值是否相等,则用s1.equals(s2)
//明天内容
String中的成员方法:
一:判断
s1.equals(s2)
s1.equalsIgnoreCase(s3) //忽略大小写
18-11-13:字符串的方法、主类中的方法注意事项提醒、next与nextLine区别.txt****
String对象的判断方法:
s1.equals(s2)
s1.equalsIgnoreCase(s2) //忽略大小写
s1.endsWith("lo")
s1.startWith("he") //判断开头和结尾字符串
String的获取方法:
s.length() //注意,对于数组来说是a.length
s.charAt(1) //根据所以获取字符,返回的是单个字符
s.substring(0, 5) //从0到4,截取字符串 左闭右开
字符串的遍历:
for(int i = 0; i < s.length(); i++){
System.out.println(s.charAt(i));
}
String的转化功能:
转化成字符数组:
char[] chs = s.toCharArray();
System.out.println(chs); //字符数组打印的是一个值,有别于其他数组,其他数组打印的是引用地址值。
for(int i = 0; i < chs.length; i++){
System.out.println(chs[i]);
}
转化成字符串小写:
s.toLowerCase()
转化成字符串大写:
s.toUpperCase()
String的其他操作:
s.trim() //返回一个去除了前后空格的字符串
s.split(",") //接收一个字符串,然后利用该字符串为切割点,将原字符串转化成字符串数组。
关于主类中的方法注意事项:
测试类(主类)中的方法一定要写成public static 类型 方法名(..){}
而类中的方法一定要写成public 类型 方法名(..){}
关于scan.next与scan.nextLine方法区别:
注意,不管怎么输入,回车是指输入完毕!
next只节选空格前的内容
nextLine是节选输入的一行的内容
18-11-14:StringBuilder的构造方法、添加与反转、链式编程、与字符串的相互转化.txt****
StringBuilder与String的区别:
为什么要有StringBuilder?:
因为每一次的字符串拼接都会浪费时间和存储空间,造成内存垃圾。
而StringBuilder是一个可变的字符串对象,合理的解决了这个问题。
StringBuilder构造方法及其容量和长度:
StringBuilder sb = new StringBuilder(); //默认构造方法,长度为16
sb.length() // 此字符串的字符个数
sb.capicity() // 该对象的容量值,理论容量
StringBuilder的添加方法及其反转功能:
StringBuilder sb = new StringBuilder();
//字符串的添加方法,链式编程。
sb.append("hello").append("world").append(true).append(100); //append方法不管添加什么都可以,且sb对象直接可变。
System.out.println(sb); //结果:helloworldtrue100
//字符串的反转方法
sb.reverse(); //reverse方法也是可以直接可变的。
System.out.println(sb); //结果:001eurtdlrowolleh
StringBuilder 与 String的相互转化:
/*
* String 与 StringBuilder的相互转化:这样可以通用各自的方法
*/
//String转化成StringBuilder:通过构造方法
String s = "hello";
StringBuilder sb = new StringBuilder(s);
System.out.println(sb);
//将StringBuilder转化成String:调用sb对象的toString方法
StringBuilder sb2 = new StringBuilder("hahah");
String s2 = sb2.toString();
System.out.println(s2);
18-11-16:ArrayList集合及其相关操作、缓冲流的问题提出.txt****
ArrayList:
缘由:因为此类是一个可以变化的数组,更加贴近实际应用。
初始化:
ArrayList<String> List = new ArrayList<String>(); //<>当中的是范型,这里以String举例。
添加元素方法:
boolean add(E e) 将指定的元素添加到此列表的尾部。
void add(int index, E element) 将指定的元素插入此列表中的指定位置。
打印:
System.out.println(List); //结果:[C++, java, python, perl, php] 不同于其他引用类型变量,和String一样,直接打印值。
长度、删除、修改、获取等方法:
E set(int index, E element) //修改
int size() //长度
E get(int index) //获取
E remove(int index) //删除
boolean remove(Object o) //删除
遍历:
通过size方法和get方法对其进行遍历。
for(int i = 0; i < List.size(); i++){
String s = List.get(i);
System.out.println(s);
}
为什么输入数字以后不能输入字符串?
输入数字以后会有个空白字符留在缓冲流之中,这个时候打一个 scan.nextLine()就可以解决这个问题。
具体内容以后再说。
18-11-16:StringBuilder的内容补充.txt****
利用StringBuilder 判断是否为对称字符的注意:
public static boolean isReverse(String s){
StringBuilder sb = new StringBuilder(s);
sb.reverse();
return sb.equals(s); //sb和s是不同的对象,不管怎么样都返回是false。
} //改成 return sb.toString().equals(s) 就可以了
由于SB对象是一个可变的引用数据,故两个变量引用同一个对象时互相影响:
StringBuilder sb = new StringBuilder("abc");
StringBuilder s = sb; //s也指向sb的对象
s.reverse(); //将s反转
System.out.println(sb); //sb也被反转了。结果:cba
18-11-18:IO流fw和fr的使用、br和bw的使用、文本复制、nextInt后不能直接nextLine的解释.txt****
IO流
简述:
用于数据的读取和存储
输入流:从文件中读取数据
输出流:将数据存储在文件当中
FileWriter的基本使用:
public class IODemo {
public static void main(String[] args) throws IOException {
//创建fw对象,注意路径的格式是\\
FileWriter fw = new FileWriter("D:\\1.txt");
//写入内容
fw.write("大家好我是熊汝成hahaha");
//写入的内容还在内存缓冲区,需要进行刷 新才能将内容填入文件当中
fw.flush();
//关闭文件
fw.close();
}
}
flush与close的区别:
flush是刷新内存缓冲区的内容,让其内容填入到文件当中
close是先将进行flush的功能,在将文件关闭
追加与换行:
如果需要追加内容就是:FileWriter fw = new FileWriter("1.txt",true);
如果需要换行:直接fw.write("\n"); //windows的记事本无法显示,需要加一个\r\n
读取数据:
int ch; //fr.read返回int,是什么类型就用什么类型接收
while((ch=fr.read())!=-1){
System.out.print((char)ch); //将int类型强制转化成char
}
一次读取多内容数据:
FileReader fr = new FileReader("1.txt");
char[] chs = new char[1024]; //默认定义为1024的整数倍
int len;
while((len=fr.read(chs))!=-1){ //fr.read(chs) 将返回获取的内容的实际长度,-1表示没有内容了
System.out.print(new String(chs,0,len)); //将字符数组转化成字符串
}
复制文本内容-两种方式进行比较:
public static void copyBySoloChar(FileWriter fw,FileReader fr) throws IOException{ //单个字符
int ch; //ch是每一个字符的编码值
while((ch=fr.read())!=-1){
fw.write(ch);
}
}
public static void copyByCharArray(FileWriter fw,FileReader fr) throws IOException{ //以字符数组
char[] chs = new char[1024]; //获取的每一个字符放在数组中
int len; //len是获取的实际长度
while((len=fr.read(chs))!=-1){
fw.write(chs, 0, len); //将实际获取的文本写入到文件中
}
}
缓冲流:
相比于FileWriter与FileReader更加高效
构造方法:
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
BufferedReader br = new BufferedReader(new FileReader("1.txt")); //构造方法里边的是fw或者fr对象
bw与br对象的特殊功能:
bw的特殊功能:
for(int i = 0; i < 10; i++){
bw.write(i+""); //将i转化成字符串
bw.newLine(); //特殊的换行功能
}
br的特殊功能:
String line;
while((line=br.readLine())!=null){ //每次读取一行中换行符前面的内容
System.out.println(line);
}
利用特殊功能进行文本复制: //必须掌握
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
关于nextInt后面为什么不能用nextLine:
使用nextInt会将换行符前面的数字输入进去,而换行符留在了缓冲区。
使用nextLine会将缓冲区中包括换行符在内的内容输入进去。
由于nextInt后还有个\n在缓冲区,当执行nextLine后就将\n输入了进去,于是就造成了问题。
改进:
x = scan.nextInt();
scan.nextLine(); //用于缓冲
s = scan.nextLine;
18-11-20:IO流的定位、static关键字、代码块.txt****
IO流的定位:
File file = new File("xxxx.txt"); //定义一个文件对象
BufferedReader br = new BufferedReader(new FileReader("xxxx.txt")); //构建一个缓冲输入流
br.mark((int)file.length()+1); //先开始,光标指在文章的开头,现在在此处标记一下,参数是字符个数,如果光标输出字符数>=该值,则无法返回到标记处
br.reset(); //让光标回到标记的位置
static关键字:
被static修饰的属性特点:
被对象共享,一个对象的该属性变了,其他对象的该属性也跟着变了。
可以直接由类名调用。
注意事项:
静态方法只能用静态的属性和方法。
非静态方法什么都可以调。
静态的方法里不可以有this关键字。
原因:
静态的方法和属性是随着类的加载而生成的,此时对象还没有出现,那些非静态属性和方法也没有生成。
为什么主类中的方法都是静态的?:
因为主方法是静态的,上面也提到静态方法只能调用静态的,所以主类中的方法也是静态的。
静态的意义:
如果将属性、方法都定义为静态的,将构造方法也私有(无法创造对象),此类就是一个工具类。
由于不需要创造对象,靠类名就能直接调用。
代码块:
就是大括号,大括号里面的变量不能出去使用。
构造代码块和静态代码块:
主要是在创造类的对象时做的初始化工作,可能构造方法过多,所以将构造方法中同样的初始化方法放在代码块中
例如:
{
System.out.println("老师对象创立成功"); //代码块,没创造一个对象就会调用
}
public Teacher(){
System.out.println("我是无参");
}
public Teacher(String name, int age){
System.out.println("我是有参");
this.name = name;
this.age = age;
}
结果: //类中代码块的执行早于构造方法,如果代码块换成static{},则"老师对象创立成功"只执行一次
老师对象创立成功
我是无参
老师对象创立成功
我是有参
18-11-21:继承的原因、继承中属性和方法的特点、方法重写注意事项、构造方法的继承问题.txt****
继承:
为什么要用到继承:
如果很多个类有相同的部分,可以将相同的部分抽取出来变成一个父类。
再让这些类继承于父类。
java中继承的特点:
只能单继承。
可以多层继承
继承中成员变量的特点:
1:子类只能继承父类中的非私有属性,对于私有属性无法继承,但可以继承父类中的pulic getElement()方法,间接获取父类的私有属性。
2:Father中有一个name,且Son中也有一个name,可让Son类通过super关键字访问父类中的name,也可以访问其他属性和方法,具体用法类似于this
继承中成员方法的特点:
1.子类只能继承父类中的非私有方法,对于私有方法无法继承
2.如果子类中的方法和父类中的方法完全相同,这叫做方法重写。一般是父类的方法无法满足子类的需求,也可以通过super硬性调用父类方法
方法重写的应用场景和注意事项:
通过注解@Override可以得到以下的结论:
1:方法重写的必须是父类中完全一样的方法!只是代码块中的东西可能不一样!
2:继承的方法权限必须宽松或者等于父类中的方法权限。(一般权限相等)
构造方法的继承:
不管如何,在初始化子类前肯定会先初始化父类,因为子类可能要用到父类的初始化东西。(重点)
子类中的构造方法如果没有写super和this关键字,则会默认调用父类的无参构造。
如果想改变默认构造,可在子类构造方法中调用super(...)关键字
18-11-22:抽象类及其注意事项、final关键字、修饰符位置问题.txt****
抽象:
为什么要抽象:
dog和cat都有eat方法,但eat不同的东西。如果直接继承Animal的eat无法满足,所以将Animal的eat方法抽象化,再让dog、cat去具体实现。
abstract 关键字:
修饰类和方法。
一般放在public 的后面(当然放在public前面也没关系)
例如:
public abstract class Animal{}
public abstract void eat();
注意点:
1.含抽象方法的类必定是抽象类,必须要用abstract去修饰类和方法。
2.抽象类的子类要么完全实现父类的所有抽象方法,要么也定义为一个抽象类。
3.抽象类中可以有非抽象方法。
4.抽象类不可以实例化,即不可用抽象类来创建对象。
抽象类中的成员特点:
1.抽象类中可以有属性。
2.抽象类中可以有抽象方法也可以有具体方法。
3.抽象类虽然不能实例化但是也可以有构造方法。因为初始化子类前要初始化父类。
4.抽象类不能是final类。因为final类没办法被继承,而abstract必须有子类实现。
5.抽象类可以有常量(即final属性)
final:
1:被final修饰的属性是常量,最好一开始就赋值(也可以在构造方法中赋值)。一旦赋值不可再次修改。
2:被final修饰的方法无法被子类重写。
3:被final修饰的类无法被继承。
有关修饰符的位置问题:
public static abstract final 这几个修饰符的位置放置关系没有关系。
但方法名的前面必须是返回类型便可。
抽象类也可以继承一个普通类。
18-11-25:多态、上下转型对象.txt****
多态:
概念:
如果父类的引用指向了子类的实体,这时同种类型调用同种方法可能会出现不同的现象,这种现象叫多态。
前提:
1.有子父类。
2.父类引用指向子类实体。
上转型和下转型:
上转型:父类引用指向子类对象。
Father ob = new Son(); //称ob是new Son()的上转型对象。
下转型:强制将上转型对象转化成子类对象。
Son ob2 = (Son)ob; //将ob这个上转型对象强制转化成子类对象,并赋给子类对象ob2,这个时候ob2就是个正宗的Son对象了
上转型对象的成员特点:
1.成员变量:
看左用左,父类必须有该变量,若子类有同名新变量,还是用的还是父类的成员变量。
2.静态方法:
看左用左,父类必须有该静态方法,若子类重写该方法,还是用的还是父类的该静态方法。
3.成员方法:
看左用右,父类必须有该方法,若子类重写该方法,用的是子类中重写后的方法!
ps:看左是指父类中必须有这个玩意儿。否则无法通过编译器
多态中的成员特点总结:
调用成员方法和属性时父类必须要有该方法或属性,否则编译器无法通过。 (意思是不可调用子类新增)
只有调用成员方法时是调用子类重写方法,其他的都是调用父类本有静态方法或属性。
18-11-25:接口、匿名对象.txt****
接口:
接口出现的原因:
为了解决继承的单一性。
有关接口的基本要点:
1.接口是一个比抽象类还抽象的类,它的所有方法都是抽象方法。
2.接口与类的关系不再是继承,而是实现。
3.接口的定义格式就是将class换成interface。
4.接口也可以用来申明变量。例如:
Phone p; //其中Phone是一个接口,p一般是个上转型对象。
接口的成员特点:
1.对于成员属性,默认加上public static final修饰词,表示必须是一个可继承静态的常量。
2.对于成员方法,默认加上public abstract 修饰词
3.接口没有构造方法。
4.同抽象类一样,如果实现接口时要么重写所有方法,要么也定义为一个抽象类。
5.请将默认修饰符打出来。
接口与类之间的关系:
1.类与类:单继承。
2.类与接口:多实现。
3.接口与接口:多继承!
4.一个类也可以同时继承和实现,不过要先继承后实现。 例如:class Final extends Student implements A {}
匿名对象:
没有变量引用:
new Student() 这就是个匿名对象。
应用场景:
一般是一次性使用某个方法时用匿名对象。
18-11-26:权限修饰符、权限修饰符的使用规则.txt****
权限修饰符:
public 当前类中 当前包下不同类中 不同包下的不同类
private 当前类中
default 当前类中 当前包下不同类中
protected 当前类中 当前包下不同类中
对于修饰符的场景使用:
1.一个java文件中只能有一个类,且该类是public类。
2.所有的成员变量用private修饰。也要设置get、set方法。
3.所有的方法都用public修饰。
4.构造方法也都用public修饰,除非不想创建对象就用private修饰(工具类)。
18-11-27:Object中的toString、equals方法.txt****
Java高级API
1.String toString()方法:
是Object中的方法,用于返回对象的地址。
2.boolean equals(Object o)
是一个比较对象的地址值是否相等的方法。
18-11-27:内部类的使用.txt****
内部类:
成员内部类:
1.成员内部类就是将内部类定义在外部类的成员位置当中。
2.创建内部类对象前必须有外部类对象,所以定义格式是: Outer.Inner i = new Outer().new Inner();
源码如下:
public class MemberInnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner(); //创建内部类对象首先要有外部类对象
inner.funInnerr();
}
}
class Outer{ //外部类
public void funOuter(){ //外部类的成员方法
System.out.println("funOuter");
}
class Inner{ //内部类定义
public void funInnerr(){ //内部类的成员方法
System.out.println("funInner");
}
}
3.修饰符:
成员内部类可以直接用static修饰,这样就不需要外部类对象了。
Outer.Inner inner = new Outer.Inner();
局部内部类:
1.局部内部类定义在外部类的方法体中。
2.局部内部类所创建的对象也只能在外部类方法体中创建。
3.局部内部类一般用的不多,只做了解内容
源码如下:
public class MemberInnerClass {
public static void main(String[] args) {
Outer o = new Outer();
o.funOuter();
}
}
class Outer{ //外部类
public void funOuter(){
class Inner{ //局部内部类的定义
public void funInnerr(){
System.out.println("funInner");
}
}
Inner i = new Inner(); //局部内部类对象也只能定义在该方法之中。
i.funInnerr();
}
}
匿名内部类:
1.格式: new 类/接口(){
子类内容
};
2.代码块中是类的子类或者接口的实现类。
3.功能与匿名对象相同,一次性调用。如果想多次调用,可以运用之前的向上转型对象原理。
4.匿名内部类是同局部内部类一样必须放在方法体中。
5.匿名内部类的应用场景是当一个对象作为参数传递一次时,为了不创建一个java文件,所以用匿名内部类对象。
18-11-28:Date类常用方法、SimpleDateFormat格式化日期.txt****
Date常用方法:
构造方法:
1.Date d = new Date(); //默认获取当前系统时间
2.Date d = new Date(long time) //将毫秒值传进去,设定指定时间对象
常用方法:
1. d.toString() //打印一个不友好时间
2. d.toLocaleString() //打印一个友好时间,但已经过时
3. d.setTime(long time) //设置时间
4. d.getTime() // 获取时间毫秒
SimpleDateFormat日期格式化:
实例上演:
public class DateDemo {
public static void main(String[] args) {
//按照指定模式创立的日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日E HH:mm:ss");
//将Date日期传进去,就可以获取格式化当前时间字符串
String s = sdf.format(new Date());
System.out.println(s); //结果:2018年11月28日星期三 17:31:48
}
}
解析时间:
Date d = sdf.parse("2018年10月28日星期三 17:31:48");
System.out.println(d.toLocaleString()); //结果:2018-10-28 17:31:48
总结:
sdf对象可以将Date对象的时间按指定格式化变成一个字符串(sdf.format()),也可以将指定格式化的字符串变成一个Date对象(sdf.parse()),
它像一个中介,在Date对象 和 指定格式字符串 中相互转换。
18-11-29:Calendar类的基本使用.txt****
Calendar类的基本使用:
1.获取对象:
Calendar c = Calendar.getInstance();
2.获取时间:
syso(c.get(Calendar.YEAR)) //Calendar.YEAR是一个字段,其实是该类的常量属性
3.修改时间:
c.set(int field, int value)
4.增加时间:
c.add(int field, int amount)
18-11-29:Collection接口概述.txt****
容器:
1.基本概念:
可以装对象的东西。
2.基本树:
Collection(接口) --> Set(接口,无序不重复), List(接口,有序可重复) -->
Map(接口,键值对存储)
3.Collection接口中的基本方法:
见API
18-11-29:包装类 Integer、字符串与整数的相互转换、自动装拆箱.txt****
包装类–Integer类的介绍:
核心内容是 int — String 的相互转化
int -> String:
方法1. number + "" // 最简单的方式
方法2.
Integer i = new Integer(10); //创立一个Integer对象,再调用对象的toString方法
System.out.println(i.toString() + 100); //10100
方法3.
String num_s = Integer.toString(20) //调用该类的静态方法 public static String toString(int i) 。
String -> int:
方法1.
Integer i = new Integer("100");
syso(i + 400); //此时i就是一个int类型,结果为500(自动拆箱)
方法2.
Integer i = new Integer("100");
int num = i.intValue(); //调用对象的方法
方法3.
int num = Integer.parseInt("1000"); //这是Integer的静态方法。
推荐:
int -> String : num + ""
String -> int: Integer.parseInt(s)
自动装箱与自动拆箱:
装箱:基本数据类型变成包装类对象。
拆箱:相反
自动装箱应用场景:
Integer i = 10; //将10这个基本数据类型转化成对象
ArrayList list = new ArrayList();
list.add(1) ; //集合只能装对象,这里的1被自动装成对象
自动拆箱应用场景:
Integer i = 10;
int num = i; //这里i被自动拆成基本数据类型,然后由基本数据类型接收
18-11-4:注释、变量、命名、转化.txt****
Java基础
·java跨平台:因为在不同的操作系统上有不同的jvm
jre:运行环境(包括jvm和核心类库)
jdk:开发工具(包括了jre)
·注释:
// 单行注释
/* */ 多行注释
/** **/文档注释
·定义数据类型时的注意:
整形默认是int
浮点默认是double
定义long时数字后加L
定义float时数字后加F
·命名规则:
包:一定要小写,多级包用.分隔
类:首字母大写
方法和变量:首字母小写,后面每个单词首字母大写
·变量的域:
变量的使用,只能在其域中(此变量所在的大括号范围中)
例如
public class Main{
public static void main(String args[]){
{ /*
代码块
*/
int c = 30;
}
System.out.print(c); //无法正常输出
}
}
·类型转换:
一般而言我们要求运算的类型一致
如果不一致就会发生转换:
隐式转换:
byte、short、char -- int -- long -- float -- double (由低向高的转换顺序)
参与运算的数据将自动转换成精度较高的数据,但高精度不可转化为低精度,避免造成缺失数据
例如:
byte a = 10;
int b = 20;
byte x = a + b; //b是int,a将转化成int,最终结果也为int,不可用低精度的变量接收
int y = a + b;
System.out.println(x);
System.out.println(y);
强制转换类型:
强制将高精度转换成低精度,一般不这样做。
例如:
如上
byte x = (byte)(a + b); //这个时候就可以通过编译
18-11-5:字符串加法、双&、随机数、数组.txt****
·字符串参与加法运算
任何类型变量与字符串参与加法运算都是字符串的拼接
System.out.println("a"+100); //a100
System.out.println("a"+'e'); //ae
·&& 与 & 以及 || 与 | 在java中区别不大
但是&&在条件判断中如果前者为false后者不进行判断,而&无论如何两边都会去进行判断
·随机数
用 ctrl + shift + o 快捷键导包
import java.util.Random;
Random r = new Random();
r.nextInt(100); //[0,100) 的随机数
·数组
基本使用
int arr[] = new int[10]; //数组的初始化
System.out.println(arr); //打印的是地址值
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]); //每一个对象进行初始化时都有一个默认值,int的默认值是0
}
静态初始化:
int[] a = {1,2,3};
for(int e: a){ //类似于python的遍历
System.out.println(e);
}
将数组赋值给数组
int[] a1 = new int[3];
int[] a2 = new int[10];
for(int i = 0; i < a1.length; i++){ //对a1数组赋值
a1[i] = i;
}
a2 = a1;
System.out.println(a2.length); //尽管a2分配了10个空间,但a2这个变量指向了a1这个变量的地址,故a2的长度也变成了3
for(int i = 0; i < a2.length; i++){
a2[i] = 100 + i; //对a2进行赋值
}
for(int i = 0; i < a2.length; i++){
System.out.println(a1[i]); //发现对a2的赋值影响到了a1
}
数组内存分配
变量名放于栈中:
int[] arr
对象放于堆中,每个对象都有默认值:
new int[100]
遍历二维数组:
int[][] a = {{1,2,3},{4,5,6},{7,8,9}};
for(int i = 0; i < a.length; i++){
for(int j = 0; j < a[i].length; j++){ //a[i]也是个数组
System.out.print(a[i][j] + " ");
}
System.out.println();
}
18-11-6:方法定义格式、方法重载、以及注意事项、方法参数是基本类型.txt****
·方法:
定义在主类当中
格式:记住格式!
public static int fun(int a, int b){
}
方法重载:
定义:
同一个类中出现了名字相同的方法参数
特点:
同名方法参数个数不一样
同名方法参数类型不一样
如果不满足以上两点:
则报错
注意:
方法重载只比较参数,即只比较参数的个数和类型。对于参数的名字和方法返回类型不予考虑。
整数默认是int,小数默认是double:
例如:
public static void main(String[] args) {
System.out.println(fun(12.0,13.0)); //由于默认小数是double,所以调用double方法
}
public static boolean fun(double a, double b){
System.out.println("double");
return a == b;
}
public static boolean fun(float a, float b){
System.out.println("float");
return a == b;
}
如果想要调用float方法,要么在小数前加转化类型,要么在小数后加f
如果方法的参数是基本数据类型:
则方法对变量的操作不影响实参
例如:
change(a,b) //a还是a,b还是b,不会交换
18-11-8:方法参数是引用类型、断点调试、面向对象格式、初始化值问题、内存分配(重点).txt****
·如果方法的参数的类型引用型参数,方法会影响该引用型变量
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
change(arr); //将arr作为参数传进去
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]); //此时数组的元素全部乘了2
}
}
public static void change(int[] a){
for(int i = 0; i < a.length; i++){
a[i] *= 2;
}
}
·断点
基本操作和Dev C++ 一样
·面向对象:
类中的方法定义:
public int fun(..) // 去掉主类中的static
类中的属性可以不用设值,原因请参考"初始化值的问题"
.初始化值的问题:
在java中数组在定义时每个元素有初始化值;
构建类时,每个属性也有初始化值;
除了数组和类以外,其他所定义的任何变量都没有初始化值。
例如:
int i;
String s;
syso(i);
syso(s); //都是The local variable 变量名 may not have been initialized
原因分析:
如果定义一个基本数据类型,它们是放在栈中,值也保存在栈中,没有赋予初始值,要使用前必须赋值。
而数组和对象是new出来的,它们保存在堆中,堆内存一开始就为它们赋予了初始值
JAVA变量内存分配:
方法区:
javac编译后的 字节码文件 都放在 方法区 中,每个字节码文件就是一个类(这也是为什么类名要和文件名一致)。
方法 和 属性 也在方法区中的 字节码文件 。
栈:
当 调用某方法 时就会将方法 加载到栈 中,方法中的变量也会加载到栈中。
如果这些变量是 基本数据类型,其值和变量一起放在栈中。而且变量 没有初始值 。
如果是 引用类型,其引用变量和其对象的 地址 也一起放在栈中, 指向堆 中的具体对象。
如果栈中的方法执行完,其分配的内存就自动被垃圾回收机制回收。
堆:
如果是new出来的引用数据,就放在堆中。
堆中对象的属性一般是基本数据类型,且都有初值。
堆中存储对象的方法只是 存储其在方法区的地址 。
18-12-10:多异常处理顺序、finally、IO流标准处理异常格式、异常分类、自定义异常(代码)、异常总结.txt****
多个异常的处理:
允许处理多个异常,平级异常次序不重要。
有子父级关系的话:子异常一定放在父异常前面。(如果父异常在前,那么就轮不到子异常处理,编译都通过不了)。
finally–不管try…catch处理异常是否成功,finally中一定执行。
例如:
try {
System.out.println(5 / 0);
}
catch(NullPointerException e) { //上面的异常无法捕获到。
System.out.println("空指针");
}
finally {
System.out.println("释放资源");
}
结果:
释放资源 //即使try..catch没有处理成功,但finally一定执行。
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.异常处理.TryCatchDemo.main(TryCatchDemo.java:11)
IO流的异常处理格式(标准格式):
FileWriter fw = null; //将fw对象初始化,防止空指针异常,以后也一定写成这种样子。
try {
fw = new FileWriter("a.txt");
fw.write("aaaaa");
}
catch (IOException e) {
System.out.println("出现IO流异常");
}
catch (Exception e) {
System.out.println("出现其他异常");
}
finally {
try {
if(fw != null) { //fw非空才将其关闭。
fw.close();
}
}
catch (Exception e) {
System.out.println("关闭时发生异常");
}
}
异常的分类:
运行时期异常:可以不处理,且一定是java.lang.RuntimeException的子类。
编译时期异常:写完必须处理,否则系统不准运行。非java.lang.RuntimeException的子类。
throw 与 throws:
throw是一种制造异常的方式。
throws是一种处理异常的方式,是无法处理异常然后抛出去给调用者处理的方式。
自定义异常:
定义编译异常:只要继承Exception,然后写好构造方法就可以了。
定义运行异常:只要继承RunTimeException然后写好构造方法就可以了。
自定义异常的例子(定义一个编译时期异常):
MyException.java
能够产生异常对象的类
public class MyException extends Exception {
各种构造方法...
}
Demo.java
public class Demo {
public static void main(String[] args) {
try {
checkScore(111); //由于定义的是编译时期异常,要么处理,要么抛给虚拟机,总之一定要处理
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//此方法用于决定是否生成异常对象。如果满足条件则抛出异常。
public static void checkScore(int score) throws MyException { //由于可能会产生异常,所以一定要在方法后面加上抛出哪种异常的可能。
if(score > 100 || score < 0) {
throw new MyException("成绩异常"); //如果抛出异常代表着方法的结束
}
System.out.println("成绩正常"); //如果没有抛出,则方法会一直执行到这。
}
}
结果: 成绩异常
总结:
1.不管try..catch处理异常是否成功,finally中一定执行。
2.FileWriter fw = null; 以后声明对象时一定设置为null。
3.如果抛出异常,其所在的方法名后一定要加上"throws 异常类型"!!这是为了告诉虚拟机此方法可能会抛出xx异常。
4.如果抛出运行异常,可以不用在方法后面throws,但是最好加上!!
5.如果一个方法throws 编译异常,不管该方法是否有无throw异常,调用此方法时一定要进行处理!一定要处理!
6.方法中如果抛出了异常(throw),则该方法就结束了。
7.父异常要后catch
18-12-12:File类的概述、构造方法、创建、删除、获取、修改、判断功能.txt****
File类的使用:
概述:
File可创建一个指向文件或者文件夹路径的对象,并可以进行一系列操作。
构造方法:(注意:该文件或者文件夹不一定存在)
File(File parent, String child)
parent是一个文件夹的file对象,child是文件名称
File(String pathname)
一个文件或者文件夹的绝对路径
File(String parent, String child)
parent是文件夹路径,child是文件的名称
创建功能:
boolean createNewFile()
创建文件
boolean mkdir()
只能在已经存在的目录中创建创建文件夹。
boolean mkdirs()
可以在不存在的目录中创建文件夹。
删除功能:
boolean delete()
可以删除文件或者文件夹,但如果文件夹下有子文件或子文件夹,则无法删除。(安全起见)
判断功能:
boolean isAbsolute()
测试此抽象路径名是否为绝对路径名。
boolean isDirectory()
测试此抽象路径名表示的文件是否是一个目录。
boolean isFile()
测试此抽象路径名表示的文件是否是一个标准文件。
boolean exists()
测试此抽象路径名表示的文件或目录是否存在。
boolean isHidden()
测试此抽象路径名指定的文件是否是一个隐藏文件。
获取和修改功能:
File getAbsoluteFile()
返回此抽象路径名的绝对路径名形式。
String getAbsolutePath()
返回此抽象路径名的绝对路径名字符串。
String getName()
返回由此抽象路径名表示的文件或目录的名称。
String getParent()
返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
File getParentFile()
返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。
String getPath()
将此抽象路径名转换为一个路径名字符串。
boolean renameTo(File dest)
重新命名此抽象路径名表示的文件。
String[] list()
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
File[] listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
18-12-13:IO流分类、用字节流进行图片复制、提一下标准输入出流、以后采用数组复制方式.txt****
IO流高级:
IO流分类(按数据类型):
字节流:
字节输入流: InputStream
字节输出流: OutputStream
字符流:
字符输入流: Reader
字符输出流: Writer
用字节流复制图片:
public static void Chars() throws FileNotFoundException, IOException {
//创建对象
FileInputStream fis = new FileInputStream("C:\\Users\\熊汝成\\Pictures\\Saved Pictures\\timg .jpg");
FileOutputStream fos = new FileOutputStream("裴秀智.jpg");
byte[] bs = new byte[1024];
int len;
while ((len = fis.read(bs)) != -1) {
fos.write(bs, 0, len);
}
fis.close();
fos.close();
System.out.println("成功");
}
注意点:
1.字节流不需要flush,字符流才需要flush。
2.以后用数组方式进行复制,高效。
标准输入输出流:
System.in 标准输入流:用于录下键盘中输入的数据
System.out 标准输出流:用在在终端中输出数据
18-12-16:isr与osw的介绍、字符流的操作,字节流的功能.txt****
1.OutputStreamWriter的引用–问题:将数据输出到终端
//输入流对象建立
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//标准输出流对象的建立
OutputStream os = System.out; //多态
String line;
while ((line = br.readLine()) != null) {
os.write(line.getBytes()); //必须将字符串转化成字节流数组才可以
os.write("\n".getBytes());
}
br.close();
os.close();
从上可以看出,当使用OutputStream写入必须是字节或字节数组,现在不想将字符串传换成字节数组。引入OSW
------------------------------------------------------------------------------------
改进源码
//输入流对象建立
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//标准输出流对象的建立
OutputStreamWriter osw = new OutputStreamWriter(System.out);
String line;
while ((line = br.readLine()) != null) {
osw.write(line); //像字符流一样的操作了
osw.write("\n");
}
br.close();
osw.close();
2.终端写入数据:
InputStream is = System.in;
FileWriter fw = new FileWriter("abc.txt");
byte[] bs = new byte[1024];
int len;
while ((len = is.read(bs)) != -1) { //is只能读字节数组
fw.write(new String(bs,0,len)); //把字节数组转化成字符串
fw.flush();
}
is.close();
fw.close();
-----------------------------------------
改进:
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
FileWriter fw = new FileWriter("abc.txt");
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
fw.write(chs,0,len);
fw.flush();
}
is.close();
fw.close();
总结:
InputStreamReader和OutputStreamWriter还是字符流,是包装了字节流的字符流!
他们构造方法中传入字节流对象,然后操作上就是字符流的操作。
这样做到了"字节流的功能,字符流的操作"
18-12-18:字符打印流的概述.txt****
打印流PrintWriter:
概述:
同FileWriter一样,也可以对文件进行写入字符流数据。
复制文本:
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//pw的构造方法很多,此构造方法是为了打开自动刷新的功能
PrintWriter pw = new PrintWriter(new FileWriter("D:\\abc.txt"), true);
String line;
while ((line = br.readLine()) != null) {
pw.println(line);
}
/*
* 即使没有刷新,没有关闭文件,同样也能进行自动刷新和换行。
*/
18-12-18:对象操作流的使用.txt****
对象操作流:
概述:可以将对象输入到文件当中。
ObjectInputStream:
构造方法:传入一个InputSteam及其子类的对象。
读取对象的方法:ois.readObject() 抛出编译异常ClassNotFoundException(如果这个对象的类找不到了)
读取文本对象的方法:
方法一:如果文件中全是对象
try {
while (true) {
Object o = ois.readObject();
System.out.println(o);
}
} catch (EOFException e) {
System.out.println("文件读完");
}
方法二:如果文件中是一个集合
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student student : list) {
System.out.println(student);
}
ObjectOutputStream:
构造方法:传入一个OutputSteam及其子类的对象。
写入对象的方法:oos.wirte()
注意:
1.构造方法一定是传入一个字节输入流或者字节输出流。
2.写入的对象一定要实现Serializable这个接口。
18-12-19:IO流的大总结.txt****
IO流的总结:
File:是指向文件或者文件夹路径的一个对象。
知识点:
构造方法、创建、删除、获取、判断、修改等功能。
FileInputStream、FileOutputStream:对文件的读写(以字节为单位)
知识点:
构造方法:
传入File对象或者String(传入String其实是自动创建File对象)
主要方法:
int read()---返回数字。
int read(byte[] b)---将字节流存到byte数组中。
void write(byte[] b, int off, int len) ---将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(int b)--- 将指定字节写入此文件输出流。
注意要点:
不管是读还是写,都是以字节byte为单位。
写入数据不需要flush刷新。
FileReader、FileWriter:对文件的读写(以字符为单位)
注意要点:
大部分知识点和fis、fos一样。
写可以写入各种数据类型(String、int、char...),但读写都是以char为基本单位。
写入数据需要flush刷新。
InputStreamReader、OutputStreamWriter:字节流的功能字符流的操作
知识点:
构造方法:
传入InputStream、OutputStream子类的对象。
注意要点:
该类的方法同Reader、Writer的操作是一样的。它是将字节流的能力包装成字符流的操作。
PrintWriter:打印流
知识点:
构造方法:
传入File、Writer、OutputStream都可以
注意要点:
其实同FileWriter类似,不过他有自动刷新和自动换行的功能。
BufferedWriter、BufferedReader:缓冲流
知识点:
构造方法:
传入Reader、Writer对象。
注意要点:
能够更加高效的处理字符流。
可以读取一行和独特的换行功能。
ObjectInputStream、ObjectOutputStream:对象操作流
知识点:
构造方法:
传入InputStream、OutputStream对象
主要方法:
readObject() 抛出编译异常ClassNotFoundException ,读完所有对象会抛出EOFException
writeObject() 写入对象
注意要点:
加入的对象的类必须实现接口Serializable
总而言之:
1.fis,fos,fw,fr的构造方法都是传入File对象。主要方法是read和write,写的单位是byte和char。字节不刷新字符要刷新。
2.br和bw把fr与fw包装进去,能够提供高效。newLine和readLine是独特方法。
3.对象操作流的构造方法是传入字节流(一般是FileInputStream和FileOutputStream),加入的对象一定要实现接口。读对象可能
找不到类所以抛出一个编译异常,读完文件会抛出一个运行异常。
18-12-20:Properties与IO流的结合.txt****
Properties与IO流的结合: 有种专门的文件是 xxx.properties
Properties的概述:
类似于Map,但键值对只能是String。被称为属性列表。
基本功能:
存数据:
setProperty(String key, String value)
拿数据:
getProperty(String key)
遍历数据:
Set<String> stringPropertyNames() 可以获取所有的键集
源码演示:
//创建Properties对象
Properties pro = new Properties();
//存入数据
pro.setProperty("001", "xrc");
pro.setProperty("002", "lw");
//遍历
Set<String> keys = pro.stringPropertyNames(); //获取到了所有的键。
for (String key : keys) {
String value = pro.getProperty(key);
System.out.println(key + "=" + value);
}
-------------------------------------------------------------------------------------------------
与IO流的结合:
具体方法:
写出数据:
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
读入数据:
void load(InputStream inStream)
void load(Reader reader)
源码演示:
/*
* 将属性列表放入到文件当中
*
*/
//创建属性列表对象
Properties prop = new Properties();
//创建输出流对象
FileWriter fw = new FileWriter(new File("学生"));
//添加键值对关系
prop.setProperty("001", "熊汝成");
prop.setProperty("002", "刘威");
prop.setProperty("003", "周玄");
//将关系存放到文件当中
prop.store(fw, "存放学生对象");
//释放资源
fw.close();
===========================================
/*
* 将文件中的关系读入到属性列表中
*/
//创建一个空的属性列表
Properties prop = new Properties();
//创建输入流对象
FileReader fr = new FileReader(new File("学生"));
//从文件中读取数据
prop.load(fr);
//释放资源
fr.close();
//遍历属性列表,看是否加载成功
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
18-12-20:关于固定序列化ID的必要性.txt****
关于序列化接口ID的问题:
存入一个学生对象后,对学生类进行了修改。在进行读入的时候,就会抛出java.io.InvalidClassException异常。
原因:将学生类写好并实现序列化接口后则系统会分配一个默认的序列化ID,且每次对学生类进行修改后则序列化ID会改变。
当进行读学生操作的时候,发现读的学生类型的序列化ID和现有学生类型的序列化ID不同时,则抛出异常。
措施:在学生类写好并实现了序列化接口以后,则立马固定住序列化ID,这样无论怎么修改,ID不变。就不会抛出错误。
直接在Student类中写一个成员变量 private static final long serialVersionUID = 8846915965544563304L;
18-12-22:Map和List都实现了序列化接口、关闭最外层stream或er便可。.txt****
1.JAVA中的Map、List都是实现了序列化接口,都可以将其存到文件当中。
2.JAVA的IO包下的stream和er都是装饰者模式,只需要调用最外层的close方法就能将内部的stream或er一并关闭。
18-12-26:多线程的概述、多线程的第一种实现方式.txt****
多线程的概述:
进程:可以理解为一个程序。
单线程:一个进程中只做一件事情。安全,效率低。
多线程:一个进程中做多个事情。不安全,效率高。
执行多线程的步骤:
1.创建类并继承Thread
2.将要执行的代码放在void run()中。
3.在主方法中创建对象。
4.调用对象的start方法,该方法会自动执行run中的代码。
代码如下:
主类:
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
HerThread ht = new HerThread();
mt.start();
ht.start();
}
}
---------------------------------------------------
线程类:
public class MyThread extends Thread {
public MyThread(){
setName("熊汝成");
}
@Override
public void run() {
for (int i = 1; i < 3 ; i++) {
System.out.println("这是"+getName()+
"的第"+i+"个线程!");
}
}
}
class HerThread extends Thread {
public HerThread() {
setName("李育霖");
}
@Override
public void run() {
for (int i = 1; i < 3; i++) {
System.out.println("这是"+getName()+
"的第"+i+"个线程!");
}
}
}
结果:不唯一。
这是李育霖的第1个线程!
这是熊汝成的第1个线程!
这是熊汝成的第2个线程!
这是李育霖的第2个线程!
18-12-26:有关异常中空指针问题、学生管理系统中常出现EOF解决.txt****
关于JAVA的try中的问题:
try {
FileReader fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
fr.close(); //此时fr会亮红线
Java严格讲究代码块的域,出了域绝对找不到变量。fr是一个放在try的代码块中,fr.close()自然
找不到fr变量。修改方式:
FileReader fr = null;
try {
fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
fr.close(); //但会抛出运行异常java.lang.NullPointerException
fr首先是个null,try中的赋值语句没有成功,所以fr一直是null,修改:
FileReader fr = null;
try {
fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
if (fr != null){
fr.close();
} //这样才是正确的方式。
在写学生管理系统的时候,如果"学生.txt"是一个空文件,在构造ObjectInputStream对象时就会报EOF异常。
看看我是如何排错的:
ObjectInputStream ois = null; //先设立为null
try {
ois = new ObjectInputStream(new FileInputStream("学生")); //尝试下创立ois对象
} catch (EOFException e) {
HashMap<String, Student> map = new HashMap<String, Student>(); //如果报错就添加一个空map进去
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("学生"));
oos.writeObject(map);
oos.close();
ois = new ObjectInputStream(new FileInputStream("学生")); //再创立一次ois对象
}
18-12-2:容器中元素的遍历(转化数组、迭代器)、迭代器中的并发异常、修改迭代器中的元素也会修改原容器中的元素.txt****
元素的遍历:
方法一:转化成object数组,再进行遍历。
//方法一,转化成数组进行遍历
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("xiongrucheng");
Object[] os = c.toArray();
for(int i = 0; i < os.length; i++){
System.out.println(os[i]);
}
方法二:转化成迭代器对象,进行遍历:
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("xiongrucheng");
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
解决迭代器中的并发异常:
由于迭代器是集合的副本,必须与集合相一致。
如果迭代器中的元素没有变,但集合中的元素发生改变就会造成:Exception in thread "main" java.util.ConcurrentModificationException(并发修改异常)
如果集合中的元素没有变,修改迭代器,迭代器会影响集合的变化。
//声明一个List对象
List list = new ArrayList();
//添加三个元素
list.add("hello");
list.add("java");
list.add("xiongrucheng");
//调用list.listIterator() 制造一个列表迭代器,因为列表迭代器拥有add方法
ListIterator itor = list.listIterator();
System.out.println(list); //结果:[hello, java, xiongrucheng]
while(itor.hasNext()){
String s = (String)itor.next(); //itor.next()转化一个String对象,向下转型
if(s.equals("java")){
itor.add("python"); //注意,如果是list.add("python")会引发异常,所以是迭代器中添加元素
}
}
System.out.println(list); //[hello, java, python, xiongrucheng]
//迭代器的变化造成了原集合的变化
迭代器可以对原集合进行永久改变:
LinkedList<Student> list = new LinkedList<Student>();
//添加元素
list.add(new Student("熊汝成", 19));
list.add(new Student("刘威", 18));
list.add(new Student("李凯文", 20));
//通过迭代器进行修改,通过迭代器,将每一个元素的名字和年龄修改
Iterator<Student> itor = list.iterator();
while(itor.hasNext()){
Student s = itor.next();
s.setAge(0);
s.setName("无名氏");
}
//在进行遍历原列表
for (Student student : list) {
System.out.println(student);
}
结果:
Student [name=无名氏, age=0]
Student [name=无名氏, age=0]
Student [name=无名氏, age=0] //发现利用迭代器进行操作了以后,原集合也都改变了。
18-12-2:泛型和增强for循环.txt****
泛型:
在java的集合类中,有许许多多的泛型。
因为集合可以添加任何类型元素,泛型可以将集合像数组一样,规定添加元素的类型。
增强for循环:
for(ElemType e : 集合对象){
}
18-12-3:List中的增删查改、元素是对象时的排序(附加源码)、foreach的修改元素.txt****
List对象中的操作:
初始化: List<Student> mylist = new LinkedList<Student>();
//其实增删查改同ArrayList一样。
添加:
mylist.add();
删除:
mylist.remove();
查找:
mylist.get()
修改:
mylist.set()
排序:
Collections.sort(列表)
注意:
1.列表中的元素的类型(比如Student),一定要实现Compareble,且重写 int compareTo(E o)方法。
2.返回值是一个整形,是自己的属性与对方的属性的差值。
对于ArrayList,上述也是如此。
具体用ArrayList还是LinkedList,取决于你是增删多,还是查改多。
foreach对于元素是基本数据类型的数组修改无效,对于元素是引用类型的数组修改有效.
例如:
for (Student student : list) {
student.name = "hhh"; //list中的元素是引用数据类型,foreach修改成功
}
for(int i : intArray){
i = 20; //intArray中的元素是int,foreach不可修改
}
源码:
Demo.java
package com.sort_and_find;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<Student> list = new LinkedList<Student>();
//添加学生
list.add(new Student(1709301, "zw", 108));
list.add(new Student(1709305, "xrc", 19));
list.add(new Student(1709302, "laowang", 50));
//先输出学生
for (Student student : list) {
System.out.println(student.schoolnumber+"-"+student.name+
"-"+student.age);
}
System.out.println("------------");
//排序
Collections.sort(list);
//再输出,利用迭代器
Iterator<Student> itor = list.iterator(); //注意,迭代器也要指定泛型
while(itor.hasNext()){
Student student = itor.next();
System.out.println(student.schoolnumber+"-"+student.name+
"-"+student.age);
}
//利用二分法来查找
/*
* 利用二分法,首先要排好序
* 其次,查找是根据Student中compareTo方法比较的何种属性进行查找的
*/
int index = Collections.binarySearch(list, new Student(1709302,"laowang",108));
System.out.println(index);
}
}
Student.java
package com.sort_and_find;
public class Student implements Comparable{
int schoolnumber;
String name;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int schoolnumber, String name, int age) {
super();
this.schoolnumber = schoolnumber;
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
// TODO Auto-generated method stub
return this.age - o.age; //根据年龄比较
}
}
结果:
1709301-zw-108
1709305-xrc-19
1709302-laowang-50
1709305-xrc-19
1709302-laowang-50
1709301-zw-108 //根据年龄排序
2 //只能根据年龄进行查找
18-12-4:collections工具类中对容器的洗牌与旋转.txt****
洗牌与旋转:
Collections提供了以下方法:
洗牌:public static void shuffle(List<E>list) 可以将数据重新排列。
旋转:public static void rotate(List<E>list, int distance)
逆转:public static void reverse(List<E> list)
18-12-4:有关HashMap的相关操作,特别是遍历.txt****
散列映射(字典)的基本操作:
1.初始化:
HashMap<String, Student> map = new HashMap<String, Student>();
2.添加元素:
map.put("xiongrucheng", new Student("熊汝成", 19));
3.输出map中的元素个数
syso(map.size())
4.根据键来查询元素
Student s = map.get("xiongrucheng");
System.out.println(s); //结果:Student [name=熊汝成, age=19]
5.查询是否包含该键:
System.out.println(map.containsKey("xiongrucheng")); //结果:true
6查询是否包含该值:
System.out.println(map.containsValue(new Student("威威", 50))); //结果,false,因为两对象地址不同
7.移除:
map.remove("likaiwen");
8.遍历:
//map.values()将返回一个实现了Collection<Student>接口类创建的对象。个人理解应该是返回了一个实现了Collection的
//匿名内部类的对象。并将该对象赋值给接口变量。
Collection<Student> c = map.values();
//c因为实现了接口的方法,所以可以返回一个确确实实的迭代器。
Iterator<Student> itor = c.iterator();
//遍历迭代器
while(itor.hasNext()){
System.out.println(itor.next());
}
//当然,也可以用foreach来遍历这个对象
Collection<Student> values = map.values();
for (Student student : values) {
System.out.println(student);
}
9.清空:
map.clear();
10.键值对的遍历:
上面的8是对键或者对值的单独遍历,现在讨论键值对的遍历
方法一:
public static void Method1(Map<String, String> map) {
//通过对键的遍历,一个个的遍历Map
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + "--" + value);
}
}
方法二:
//利用Map中的内部类进行遍历
public static void Method2(Map<String, String> map) {
Set<Map.Entry<String,String>> entrys = map.entrySet(); //Map.Entry是Map中的内部类
for (Map.Entry<String, String> entry : entrys) {
System.out.println(entry.getKey()+"--"+entry.getValue());
}
}
注意点:
如何通过键进行对值的修改?
只需要重新put()就可以进行覆盖修改了
18-12-4:栈的基本操作.txt****
栈堆:
boolean empty()
测试堆栈是否为空。
E peek()
查看堆栈顶部的对象,但不从堆栈中移除它。
E pop()
移除堆栈顶部的对象,并作为此函数的值返回该对象。
E push(E item)
把项压入堆栈顶部。
int search(Object o)
返回对象在堆栈中的位置,以 1 为基数。
18-12-5:List中的排序(详解),Comparable与Comparator的区别(内外比较器的比较)、学生集合各个属性排序(完整代码).txt****
List中的排序问题:
1.对于基本数据类型:
正序
Collections.sort(list);
逆序
Collections.sort(list,new Comparator<Integer>(){ //实现一个Comparator的内部类对象
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
2.对于引用数据类型的排序:
方法一:利用匿名类实现Comparator<Student>接口
Collections.sort(list,new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
return o1.getRank() - o2.getRank(); //根据名字排序:return s1.getName().compareTo(s2.getName());
}
});
方法二:Student类中实现Comparable<Student>接口
类:public class Student implements Comparable<Student>{...}
重写方法:
@Override
public int compareTo(Student o) {
return o.rank - this.rank;
}
Comparable 与 Comparator的区别:
内比较器:Comparable形容词,表示可比较的。这种接口往往是需要类去实现的,从而增加类的一个“可比较”功能。
外比较器:Comparator表示比较器,一般是通过内部类实现该接口的功能,用于给Collections.sort()传递参数。一般推荐这种方式。
对学生的各个属性排序的完整代码:
package com.sort_and_find;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SuperDataDemo{
/*
*静态的成员内部类
*/
static class sortByName implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getName().compareTo(o2.getName());
}
}
static class sortByAge implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
static class sortByRank implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getRank() - o2.getRank();
}
}
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
//添加学生
list.add(new Student("jack", 45, 'a'));
list.add(new Student("beak", 20, 'c'));
list.add(new Student("tom", 90, 'f'));
list.add(new Student("keven", 31, 't'));
list.add(new Student("anny", 8, 'e'));
//遍历
for (Student student : list) {
System.out.print(student);
}
System.out.println();
//排序,根据xx来排序
Collections.sort(list, new sortByRank());
//遍历
for (Student student : list) {
System.out.print(student);
}
System.out.println();
}
}
18-12-9:异常的处理、抛出(初步,后续还有补充).txt****
异常处理:
1.异常体系:
超类:java.lang.Throwable--->java.lang.Error(不可扭转的的错误), java.lang.Exception(可处理的异常)
2.异常处理的方式:
捕获并处理异常
抛出异常
3.捕获并处理异常try..catch语句:
格式:
try{
可能发生异常的语句
} catch(异常类型 e){
处理语句
}
注意点:
1.发生异常后,如果没有try..catch语句,则jvm会自动关闭程序。
2.如果写了语句,发生异常后自动跳转到catch中,不会再跳回try语句中。例如:
代码:
try{
System.out.println("try的第一条");
System.out.println(4/ 0);
System.out.println("try的第二条"); //跳转到catch中,不会再回来
} catch(Exception e){
System.out.println("发生异常");
}
结果:
try的第一条
发生异常
4.抛出异常:
异常都是发生在某个方法当中,如果没能力处理或者不想处理该异常,就可以将异常抛出去,交给调用方法的人去处理。
格式:
方法名() throws 异常类型{} //注意,异常类型可以写此异常类型的父类型。
抛出异常还遗留许多问题,见后续补充
19-1-10:TCP通信的补充点.txt****
TCP协议进行数据通信的注意点:
1.
输入流--------------相互连接--------------输出流
| |
| |
| |
客户端Socket 服务端Socket
| |
| |
| |
输出流--------------相互连接---------------输入流
如图所示,客户端的Socket与服务端accept后的Socket的交错连接。
调用getInetAddress()方法获取的是对方的IP对象。
2.Java的socket是一个全双工套接字,任何的输入流或输出流的close()都会造成Socket关闭。
所以,不要用close方法关闭socket的IO流,可以用shutdown方法。
19-1-13:单元测试Junit.txt****
Junit单元测试:
在主类中的方法中添加注解@Test、@After、@Before便可进行单元测试,且方法不可是静态方法。
19-1-5:InetAddress类的简要了解.txt****
InetAddress类的介绍:
概述:此类表示互联网协议 (IP) 地址。
初始化方法:
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。 host可以是主机名,也可以是ip地址。
获取方法:
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。
19-1-5:主方法的运行是单线程的、多线程的第二种实现方法.txt****
主方法是单线程的,在主方法中调用各种方法时,程序是从上往下,从左往右运行。
实现多线程的第二种方式:
1.创建一个类实现接口Runnable,并重写run方法。
2.在主方法创建类实例mt。
3.在主方法中创建Thread实例t,并将mt对象传递进去。
4.调用start方法,开启线程.
代码如下:
主类:
public class ThreadDemo {
public static void main(String[] args) {
//创建MyThread对象
MyThread mt = new MyThread();
//创建第一个Thread对象,将mt传进去。
Thread t = new Thread(mt);
t.setName("老王");
//创建第二个Thread对象,将mt传进去
Thread t2 = new Thread(mt);
t2.setName("老张");
t.start();
t2.start();
}
}
自定义类:
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + //静态的获取当前线程的方法
"的" + i + "个线程");
}
}
运行结果:
老张的1个线程
老王的1个线程
老王的2个线程
老王的3个线程
老张的2个线程
老张的3个线程
第二种方法的意义:
第一种方法是继承,第二种方法是实现,二解决了一的多继承问题。
19-1-5:利用同步代码块或同步方法解决多线程中的并发问题.txt****
多线程可能遇到的问题:
当有多个线程。
多个线程共享一个数据源。
就有可能会造成数据重复执行等问题。
为了解决这个问题,引进同步代码块的概念。
同步代码块:
格式:
synchronized (this) {
每一个线程的运行代码。
}
作用:
当线程的运行代码被synchronized(this){}包住以后,当运行这个线程时,将会开启一个锁,其他线程暂时无法运行。
源码:
public class MyThread implements Runnable {
int count = 100; //票的总数
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) { //需要进行封锁的地方,加上同步代码块
if (this.count > 0) {
System.out.println(Thread.currentThread().getName() +
"第" + this.count + "张票正在出售");
this.count --;
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//实例化mt对象.
MyThread mt = new MyThread();
//实例化多线程窗口一
Thread t1 = new Thread(mt);
t1.setName("窗口一");
//实例化多线程窗口二
Thread t2 = new Thread(mt);
t2.setName("窗口二");
//实例化多线程窗口三
Thread t3 = new Thread(mt);
t3.setName("窗口三");
//实例化多线程窗口四
Thread t4 = new Thread(mt);
t4.setName("窗口四");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步方法:
将synchronized放在run方法前面作为修饰符修饰,就可以将整个方法锁住。
@Override
public synchronized void run() { ... } //用synchronized修饰后也是重写方法。
19-1-6:利用UDP协议发送并接收数据.txt****
使用UDP协议发送数据:
步骤:
1.创建发送端对象DatagramSocket类的对象。
2.创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
3.发送出去。
4.释放资源
创建发送端对象DatagramSocket类的对象:
使用无参构造,因为发送端不关心端口号。
DatagramSocket ds = new DatagramSocket();
创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
发送数据:
ds.send(dp);
发送端完整程序:
public class UDPSendDemo {
public static void main(String[] args) throws IOException {
//1.创建发送端对象DatagramSocket类的对象。
DatagramSocket ds = new DatagramSocket();
//2.创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
String content = "你好,我叫熊汝成";
byte[] bys = content.getBytes(); //将字符串转化成字节数组
int length = bys.length;
InetAddress address = InetAddress.getByName("192.168.190.1"); //创建InetAddress对象。
int port = 8888;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
//3.发送出去。
ds.send(dp);
//4.释放资源
ds.close();
}
}
UDP协议接收数据:
步骤:
1.创建DatagramSocket对象
2.创建Datagrampacket对象,这是一个容器,接收数据要用到
3.接收数据,将数据放在包中。
4.解包,获取包中的各项数据
5.释放资源
创建DatagramSocket对象:
注意,要与发送端的端口号一致。
DatagramSocket ds = new DatagramSocket(8888);
创建Datagrampacket:
使用DatagramPacket(byte[] buf, int length)构造便可,因为只是为了接收数据,创建一个容器便可。
接收数据,将数据放在包中:
ds.receive(dp); //这样就将数据放在了容器dp中。
解包,获取包中的各项数据:
通过dp中的各种get方法得到数据。
完整程序:
public class UDPGetDemo {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket(8888);
//2.创建Datagrampacket对象,这是一个容器,接收数据要用到
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
//3.接收数据,将数据放在包中。
System.out.println("准备接收数据");
ds.receive(dp);
System.out.println("接收到了数据");
//4.解包,获取包中的各项数据
byte[] bys = dp.getData();
InetAddress address = dp.getAddress();
int length = dp.getLength();
String content = new String(bys, 0, length);
System.out.println("sender -->" + address.getHostName());
System.out.println("content -->" + content);
//5.释放资源
ds.close();
}
}
注意:在第75行会有发生堵塞,打开接收端后程序会一直运行,直到收到消息。
19-1-9:利用TCP协议进行数据的发送和接收.txt****
利用TCP协议进行发送数据:
步骤:
1.创建Socket对象
2.从Socket对象中获取输出流对象。
3.利用输出流发送数据
4.释放资源
创建Socket对象:
Socket(InetAddress address, int port) //对方的IP地址和端口号
从Socket对象中获取输出流对象:
OutputStream os = s.getOutputStream();
利用输出流发送数据:
os.write(byte[]);
利用TCP协议进行接收数据:
步骤:
1.创建ServerSocket对象。
2.利用此对象返回一个Socket对象,用于监听(堵塞)
3.获取输入流对象
4.获取数据
5.释放资源
创建ServerSocket对象:
ServerSocket ss = new ServerSocket(9999); //本机端口号
利用此对象返回一个Socket对象,用于监听(堵塞):
Socket s = ss.accept(); //在此处程序堵塞
获取输入流对象:
InputStream is = s.getInputStream();
获取数据:
String sender = s.getInetAddress().getHostAddress() + "--" +
s.getInetAddress().getHostName();
byte[] bys = new byte[1024];
int len;
len = is.read(bys);
String content = new String(bys, 0, len);
System.out.println("sender -->" + sender);
System.out.println("content -->" + content);
释放资源:
s.close();
// ss.close(); //服务端不应该关掉。
2019-1-13:JAVA的类加载机制.txt****
JAVA的类加载机制:
1.加载class文件到内存
2.将加载好的数据融合到jre这个大的环境中。
3.进行一系列初始化的工作
all.txt****
18-11-11:同类不同对象的方法指向一个区、成员变量与局部变量、私有化、构造方法及其重载.txt****
两个对象所指向的方法是同一个地址:
如果有两个对象p1,p2,他们的方法其实都是放在方法区中。
而他们的对于共同指向此方法
成员变量和局部变量区别:
位置:
成员变量是在类中声明的
局部变量是在方法体中或者形式参数中声明
内存:
成员变量是在堆中
局部变量是在栈中
初始化值:
成员变量因为是在堆中所以有初值
局部变量在栈中,所以声明后必须要先赋值才能使用
private修饰符:
放置位置:
放在变量或方法的最前面
作用:
被修饰后的变量或方法只可以在本类中使用,在外类不可见。
这样可以保证数据安全
配合:
被private修饰了的变量一定要有对应的setXxx() 和 getXxx()公有方法
构造方法:
格式:
public Student(...){ //与类名同名,且没有返回类型。
}
调用构造方法:
Student s = new Student(..) //其实new后面的就是调用了一个类的构造方法
构造方法的注意事项与重载:
如果没有构造方法,则系统会自动提供一个无参数的构造方法。
如果有了带参数的构造方法,无参构造方法就要自己构造。
推荐只要写一个类,就要有一个无参构造方法
18-11-12:方法的形参和返回值可以是对象、API、==详解、String对象初步、直接赋值和new字符串对象区别.txt****
类中的方法的形式参数和返回值可以是一个对象:
形参-例如:
public void UseStudent(Student s){
System.out.println("我是个老师,现在调用学生的方法");
s.speak();
}
返回值-例如:
public Student getStudent(){ //返回类型是类,则返回对象
Student s = new Student();
return s;
}
API的使用:
API就是帮助文档
==:
如果是基本数据类型则比较的是值是否相等。
如果是引用数据类型则比较的是地址是否相等。
String对象初步:
String是个特殊的引用类型对象
syso(str) //一般来说打印引用类型变量结果为其引用值,而打印字符串类型对象则直接打印结果
new出的字符串对象和直接赋值的字符串对象的区别比较:
new方式:
new出来的依然是在堆内存,但是字符串的内容在方法区的常量池中。
栈中的引用变量存了堆的地址,而堆中对象是存的常量池的地址。
直接赋值:
栈中的引用变量直接存的是常量池中的地址。
常量池:
字符串一般存在方法区当中的常量池中,同一个字符串在常量池中的位置唯一
举例1:
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1==s2); //false
原因分析:
s1存的是常量池当中的002;
s2存的是堆中的001,堆中的001在存的是常量池中的002;
001 != 002 所以false
举例2:
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); //true
原因分析:
s1和s2存的都是常量池中的002,所以相等。
注意: 因为字符串对象也是引用数据,所以在进行==比较的是地址的值。
如果要比较字符串的值是否相等,则用s1.equals(s2)
//明天内容
String中的成员方法:
一:判断
s1.equals(s2)
s1.equalsIgnoreCase(s3) //忽略大小写
18-11-13:字符串的方法、主类中的方法注意事项提醒、next与nextLine区别.txt****
String对象的判断方法:
s1.equals(s2)
s1.equalsIgnoreCase(s2) //忽略大小写
s1.endsWith("lo")
s1.startWith("he") //判断开头和结尾字符串
String的获取方法:
s.length() //注意,对于数组来说是a.length
s.charAt(1) //根据所以获取字符,返回的是单个字符
s.substring(0, 5) //从0到4,截取字符串 左闭右开
字符串的遍历:
for(int i = 0; i < s.length(); i++){
System.out.println(s.charAt(i));
}
String的转化功能:
转化成字符数组:
char[] chs = s.toCharArray();
System.out.println(chs); //字符数组打印的是一个值,有别于其他数组,其他数组打印的是引用地址值。
for(int i = 0; i < chs.length; i++){
System.out.println(chs[i]);
}
转化成字符串小写:
s.toLowerCase()
转化成字符串大写:
s.toUpperCase()
String的其他操作:
s.trim() //返回一个去除了前后空格的字符串
s.split(",") //接收一个字符串,然后利用该字符串为切割点,将原字符串转化成字符串数组。
关于主类中的方法注意事项:
测试类(主类)中的方法一定要写成public static 类型 方法名(..){}
而类中的方法一定要写成public 类型 方法名(..){}
关于scan.next与scan.nextLine方法区别:
注意,不管怎么输入,回车是指输入完毕!
next只节选空格前的内容
nextLine是节选输入的一行的内容
18-11-14:StringBuilder的构造方法、添加与反转、链式编程、与字符串的相互转化.txt****
StringBuilder与String的区别:
为什么要有StringBuilder?:
因为每一次的字符串拼接都会浪费时间和存储空间,造成内存垃圾。
而StringBuilder是一个可变的字符串对象,合理的解决了这个问题。
StringBuilder构造方法及其容量和长度:
StringBuilder sb = new StringBuilder(); //默认构造方法,长度为16
sb.length() // 此字符串的字符个数
sb.capicity() // 该对象的容量值,理论容量
StringBuilder的添加方法及其反转功能:
StringBuilder sb = new StringBuilder();
//字符串的添加方法,链式编程。
sb.append("hello").append("world").append(true).append(100); //append方法不管添加什么都可以,且sb对象直接可变。
System.out.println(sb); //结果:helloworldtrue100
//字符串的反转方法
sb.reverse(); //reverse方法也是可以直接可变的。
System.out.println(sb); //结果:001eurtdlrowolleh
StringBuilder 与 String的相互转化:
/*
* String 与 StringBuilder的相互转化:这样可以通用各自的方法
*/
//String转化成StringBuilder:通过构造方法
String s = "hello";
StringBuilder sb = new StringBuilder(s);
System.out.println(sb);
//将StringBuilder转化成String:调用sb对象的toString方法
StringBuilder sb2 = new StringBuilder("hahah");
String s2 = sb2.toString();
System.out.println(s2);
18-11-16:ArrayList集合及其相关操作、缓冲流的问题提出.txt****
ArrayList:
缘由:因为此类是一个可以变化的数组,更加贴近实际应用。
初始化:
ArrayList<String> List = new ArrayList<String>(); //<>当中的是范型,这里以String举例。
添加元素方法:
boolean add(E e) 将指定的元素添加到此列表的尾部。
void add(int index, E element) 将指定的元素插入此列表中的指定位置。
打印:
System.out.println(List); //结果:[C++, java, python, perl, php] 不同于其他引用类型变量,和String一样,直接打印值。
长度、删除、修改、获取等方法:
E set(int index, E element) //修改
int size() //长度
E get(int index) //获取
E remove(int index) //删除
boolean remove(Object o) //删除
遍历:
通过size方法和get方法对其进行遍历。
for(int i = 0; i < List.size(); i++){
String s = List.get(i);
System.out.println(s);
}
为什么输入数字以后不能输入字符串?
输入数字以后会有个空白字符留在缓冲流之中,这个时候打一个 scan.nextLine()就可以解决这个问题。
具体内容以后再说。
18-11-16:StringBuilder的内容补充.txt****
利用StringBuilder 判断是否为对称字符的注意:
public static boolean isReverse(String s){
StringBuilder sb = new StringBuilder(s);
sb.reverse();
return sb.equals(s); //sb和s是不同的对象,不管怎么样都返回是false。
} //改成 return sb.toString().equals(s) 就可以了
由于SB对象是一个可变的引用数据,故两个变量引用同一个对象时互相影响:
StringBuilder sb = new StringBuilder("abc");
StringBuilder s = sb; //s也指向sb的对象
s.reverse(); //将s反转
System.out.println(sb); //sb也被反转了。结果:cba
18-11-18:IO流fw和fr的使用、br和bw的使用、文本复制、nextInt后不能直接nextLine的解释.txt****
IO流
简述:
用于数据的读取和存储
输入流:从文件中读取数据
输出流:将数据存储在文件当中
FileWriter的基本使用:
public class IODemo {
public static void main(String[] args) throws IOException {
//创建fw对象,注意路径的格式是\\
FileWriter fw = new FileWriter("D:\\1.txt");
//写入内容
fw.write("大家好我是熊汝成hahaha");
//写入的内容还在内存缓冲区,需要进行刷 新才能将内容填入文件当中
fw.flush();
//关闭文件
fw.close();
}
}
flush与close的区别:
flush是刷新内存缓冲区的内容,让其内容填入到文件当中
close是先将进行flush的功能,在将文件关闭
追加与换行:
如果需要追加内容就是:FileWriter fw = new FileWriter("1.txt",true);
如果需要换行:直接fw.write("\n"); //windows的记事本无法显示,需要加一个\r\n
读取数据:
int ch; //fr.read返回int,是什么类型就用什么类型接收
while((ch=fr.read())!=-1){
System.out.print((char)ch); //将int类型强制转化成char
}
一次读取多内容数据:
FileReader fr = new FileReader("1.txt");
char[] chs = new char[1024]; //默认定义为1024的整数倍
int len;
while((len=fr.read(chs))!=-1){ //fr.read(chs) 将返回获取的内容的实际长度,-1表示没有内容了
System.out.print(new String(chs,0,len)); //将字符数组转化成字符串
}
复制文本内容-两种方式进行比较:
public static void copyBySoloChar(FileWriter fw,FileReader fr) throws IOException{ //单个字符
int ch; //ch是每一个字符的编码值
while((ch=fr.read())!=-1){
fw.write(ch);
}
}
public static void copyByCharArray(FileWriter fw,FileReader fr) throws IOException{ //以字符数组
char[] chs = new char[1024]; //获取的每一个字符放在数组中
int len; //len是获取的实际长度
while((len=fr.read(chs))!=-1){
fw.write(chs, 0, len); //将实际获取的文本写入到文件中
}
}
缓冲流:
相比于FileWriter与FileReader更加高效
构造方法:
BufferedWriter bw = new BufferedWriter(new FileWriter("1.txt"));
BufferedReader br = new BufferedReader(new FileReader("1.txt")); //构造方法里边的是fw或者fr对象
bw与br对象的特殊功能:
bw的特殊功能:
for(int i = 0; i < 10; i++){
bw.write(i+""); //将i转化成字符串
bw.newLine(); //特殊的换行功能
}
br的特殊功能:
String line;
while((line=br.readLine())!=null){ //每次读取一行中换行符前面的内容
System.out.println(line);
}
利用特殊功能进行文本复制: //必须掌握
String line;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
关于nextInt后面为什么不能用nextLine:
使用nextInt会将换行符前面的数字输入进去,而换行符留在了缓冲区。
使用nextLine会将缓冲区中包括换行符在内的内容输入进去。
由于nextInt后还有个\n在缓冲区,当执行nextLine后就将\n输入了进去,于是就造成了问题。
改进:
x = scan.nextInt();
scan.nextLine(); //用于缓冲
s = scan.nextLine;
18-11-20:IO流的定位、static关键字、代码块.txt****
IO流的定位:
File file = new File("xxxx.txt"); //定义一个文件对象
BufferedReader br = new BufferedReader(new FileReader("xxxx.txt")); //构建一个缓冲输入流
br.mark((int)file.length()+1); //先开始,光标指在文章的开头,现在在此处标记一下,参数是字符个数,如果光标输出字符数>=该值,则无法返回到标记处
br.reset(); //让光标回到标记的位置
static关键字:
被static修饰的属性特点:
被对象共享,一个对象的该属性变了,其他对象的该属性也跟着变了。
可以直接由类名调用。
注意事项:
静态方法只能用静态的属性和方法。
非静态方法什么都可以调。
静态的方法里不可以有this关键字。
原因:
静态的方法和属性是随着类的加载而生成的,此时对象还没有出现,那些非静态属性和方法也没有生成。
为什么主类中的方法都是静态的?:
因为主方法是静态的,上面也提到静态方法只能调用静态的,所以主类中的方法也是静态的。
静态的意义:
如果将属性、方法都定义为静态的,将构造方法也私有(无法创造对象),此类就是一个工具类。
由于不需要创造对象,靠类名就能直接调用。
代码块:
就是大括号,大括号里面的变量不能出去使用。
构造代码块和静态代码块:
主要是在创造类的对象时做的初始化工作,可能构造方法过多,所以将构造方法中同样的初始化方法放在代码块中
例如:
{
System.out.println("老师对象创立成功"); //代码块,没创造一个对象就会调用
}
public Teacher(){
System.out.println("我是无参");
}
public Teacher(String name, int age){
System.out.println("我是有参");
this.name = name;
this.age = age;
}
结果: //类中代码块的执行早于构造方法,如果代码块换成static{},则"老师对象创立成功"只执行一次
老师对象创立成功
我是无参
老师对象创立成功
我是有参
18-11-21:继承的原因、继承中属性和方法的特点、方法重写注意事项、构造方法的继承问题.txt****
继承:
为什么要用到继承:
如果很多个类有相同的部分,可以将相同的部分抽取出来变成一个父类。
再让这些类继承于父类。
java中继承的特点:
只能单继承。
可以多层继承
继承中成员变量的特点:
1:子类只能继承父类中的非私有属性,对于私有属性无法继承,但可以继承父类中的pulic getElement()方法,间接获取父类的私有属性。
2:Father中有一个name,且Son中也有一个name,可让Son类通过super关键字访问父类中的name,也可以访问其他属性和方法,具体用法类似于this
继承中成员方法的特点:
1.子类只能继承父类中的非私有方法,对于私有方法无法继承
2.如果子类中的方法和父类中的方法完全相同,这叫做方法重写。一般是父类的方法无法满足子类的需求,也可以通过super硬性调用父类方法
方法重写的应用场景和注意事项:
通过注解@Override可以得到以下的结论:
1:方法重写的必须是父类中完全一样的方法!只是代码块中的东西可能不一样!
2:继承的方法权限必须宽松或者等于父类中的方法权限。(一般权限相等)
构造方法的继承:
不管如何,在初始化子类前肯定会先初始化父类,因为子类可能要用到父类的初始化东西。(重点)
子类中的构造方法如果没有写super和this关键字,则会默认调用父类的无参构造。
如果想改变默认构造,可在子类构造方法中调用super(...)关键字
18-11-22:抽象类及其注意事项、final关键字、修饰符位置问题.txt****
抽象:
为什么要抽象:
dog和cat都有eat方法,但eat不同的东西。如果直接继承Animal的eat无法满足,所以将Animal的eat方法抽象化,再让dog、cat去具体实现。
abstract 关键字:
修饰类和方法。
一般放在public 的后面(当然放在public前面也没关系)
例如:
public abstract class Animal{}
public abstract void eat();
注意点:
1.含抽象方法的类必定是抽象类,必须要用abstract去修饰类和方法。
2.抽象类的子类要么完全实现父类的所有抽象方法,要么也定义为一个抽象类。
3.抽象类中可以有非抽象方法。
4.抽象类不可以实例化,即不可用抽象类来创建对象。
抽象类中的成员特点:
1.抽象类中可以有属性。
2.抽象类中可以有抽象方法也可以有具体方法。
3.抽象类虽然不能实例化但是也可以有构造方法。因为初始化子类前要初始化父类。
4.抽象类不能是final类。因为final类没办法被继承,而abstract必须有子类实现。
5.抽象类可以有常量(即final属性)
final:
1:被final修饰的属性是常量,最好一开始就赋值(也可以在构造方法中赋值)。一旦赋值不可再次修改。
2:被final修饰的方法无法被子类重写。
3:被final修饰的类无法被继承。
有关修饰符的位置问题:
public static abstract final 这几个修饰符的位置放置关系没有关系。
但方法名的前面必须是返回类型便可。
抽象类也可以继承一个普通类。
18-11-25:多态、上下转型对象.txt****
多态:
概念:
如果父类的引用指向了子类的实体,这时同种类型调用同种方法可能会出现不同的现象,这种现象叫多态。
前提:
1.有子父类。
2.父类引用指向子类实体。
上转型和下转型:
上转型:父类引用指向子类对象。
Father ob = new Son(); //称ob是new Son()的上转型对象。
下转型:强制将上转型对象转化成子类对象。
Son ob2 = (Son)ob; //将ob这个上转型对象强制转化成子类对象,并赋给子类对象ob2,这个时候ob2就是个正宗的Son对象了
上转型对象的成员特点:
1.成员变量:
看左用左,父类必须有该变量,若子类有同名新变量,还是用的还是父类的成员变量。
2.静态方法:
看左用左,父类必须有该静态方法,若子类重写该方法,还是用的还是父类的该静态方法。
3.成员方法:
看左用右,父类必须有该方法,若子类重写该方法,用的是子类中重写后的方法!
ps:看左是指父类中必须有这个玩意儿。否则无法通过编译器
多态中的成员特点总结:
调用成员方法和属性时父类必须要有该方法或属性,否则编译器无法通过。 (意思是不可调用子类新增)
只有调用成员方法时是调用子类重写方法,其他的都是调用父类本有静态方法或属性。
18-11-25:接口、匿名对象.txt****
接口:
接口出现的原因:
为了解决继承的单一性。
有关接口的基本要点:
1.接口是一个比抽象类还抽象的类,它的所有方法都是抽象方法。
2.接口与类的关系不再是继承,而是实现。
3.接口的定义格式就是将class换成interface。
4.接口也可以用来申明变量。例如:
Phone p; //其中Phone是一个接口,p一般是个上转型对象。
接口的成员特点:
1.对于成员属性,默认加上public static final修饰词,表示必须是一个可继承静态的常量。
2.对于成员方法,默认加上public abstract 修饰词
3.接口没有构造方法。
4.同抽象类一样,如果实现接口时要么重写所有方法,要么也定义为一个抽象类。
5.请将默认修饰符打出来。
接口与类之间的关系:
1.类与类:单继承。
2.类与接口:多实现。
3.接口与接口:多继承!
4.一个类也可以同时继承和实现,不过要先继承后实现。 例如:class Final extends Student implements A {}
匿名对象:
没有变量引用:
new Student() 这就是个匿名对象。
应用场景:
一般是一次性使用某个方法时用匿名对象。
18-11-26:权限修饰符、权限修饰符的使用规则.txt****
权限修饰符:
public 当前类中 当前包下不同类中 不同包下的不同类
private 当前类中
default 当前类中 当前包下不同类中
protected 当前类中 当前包下不同类中
对于修饰符的场景使用:
1.一个java文件中只能有一个类,且该类是public类。
2.所有的成员变量用private修饰。也要设置get、set方法。
3.所有的方法都用public修饰。
4.构造方法也都用public修饰,除非不想创建对象就用private修饰(工具类)。
18-11-27:Object中的toString、equals方法.txt****
Java高级API
1.String toString()方法:
是Object中的方法,用于返回对象的地址。
2.boolean equals(Object o)
是一个比较对象的地址值是否相等的方法。
18-11-27:内部类的使用.txt****
内部类:
成员内部类:
1.成员内部类就是将内部类定义在外部类的成员位置当中。
2.创建内部类对象前必须有外部类对象,所以定义格式是: Outer.Inner i = new Outer().new Inner();
源码如下:
public class MemberInnerClass {
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner(); //创建内部类对象首先要有外部类对象
inner.funInnerr();
}
}
class Outer{ //外部类
public void funOuter(){ //外部类的成员方法
System.out.println("funOuter");
}
class Inner{ //内部类定义
public void funInnerr(){ //内部类的成员方法
System.out.println("funInner");
}
}
3.修饰符:
成员内部类可以直接用static修饰,这样就不需要外部类对象了。
Outer.Inner inner = new Outer.Inner();
局部内部类:
1.局部内部类定义在外部类的方法体中。
2.局部内部类所创建的对象也只能在外部类方法体中创建。
3.局部内部类一般用的不多,只做了解内容
源码如下:
public class MemberInnerClass {
public static void main(String[] args) {
Outer o = new Outer();
o.funOuter();
}
}
class Outer{ //外部类
public void funOuter(){
class Inner{ //局部内部类的定义
public void funInnerr(){
System.out.println("funInner");
}
}
Inner i = new Inner(); //局部内部类对象也只能定义在该方法之中。
i.funInnerr();
}
}
匿名内部类:
1.格式: new 类/接口(){
子类内容
};
2.代码块中是类的子类或者接口的实现类。
3.功能与匿名对象相同,一次性调用。如果想多次调用,可以运用之前的向上转型对象原理。
4.匿名内部类是同局部内部类一样必须放在方法体中。
5.匿名内部类的应用场景是当一个对象作为参数传递一次时,为了不创建一个java文件,所以用匿名内部类对象。
18-11-28:Date类常用方法、SimpleDateFormat格式化日期.txt****
Date常用方法:
构造方法:
1.Date d = new Date(); //默认获取当前系统时间
2.Date d = new Date(long time) //将毫秒值传进去,设定指定时间对象
常用方法:
1. d.toString() //打印一个不友好时间
2. d.toLocaleString() //打印一个友好时间,但已经过时
3. d.setTime(long time) //设置时间
4. d.getTime() // 获取时间毫秒
SimpleDateFormat日期格式化:
实例上演:
public class DateDemo {
public static void main(String[] args) {
//按照指定模式创立的日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日E HH:mm:ss");
//将Date日期传进去,就可以获取格式化当前时间字符串
String s = sdf.format(new Date());
System.out.println(s); //结果:2018年11月28日星期三 17:31:48
}
}
解析时间:
Date d = sdf.parse("2018年10月28日星期三 17:31:48");
System.out.println(d.toLocaleString()); //结果:2018-10-28 17:31:48
总结:
sdf对象可以将Date对象的时间按指定格式化变成一个字符串(sdf.format()),也可以将指定格式化的字符串变成一个Date对象(sdf.parse()),
它像一个中介,在Date对象 和 指定格式字符串 中相互转换。
18-11-29:Calendar类的基本使用.txt****
Calendar类的基本使用:
1.获取对象:
Calendar c = Calendar.getInstance();
2.获取时间:
syso(c.get(Calendar.YEAR)) //Calendar.YEAR是一个字段,其实是该类的常量属性
3.修改时间:
c.set(int field, int value)
4.增加时间:
c.add(int field, int amount)
18-11-29:Collection接口概述.txt****
容器:
1.基本概念:
可以装对象的东西。
2.基本树:
Collection(接口) --> Set(接口,无序不重复), List(接口,有序可重复) -->
Map(接口,键值对存储)
3.Collection接口中的基本方法:
见API
18-11-29:包装类 Integer、字符串与整数的相互转换、自动装拆箱.txt****
包装类–Integer类的介绍:
核心内容是 int — String 的相互转化
int -> String:
方法1. number + "" // 最简单的方式
方法2.
Integer i = new Integer(10); //创立一个Integer对象,再调用对象的toString方法
System.out.println(i.toString() + 100); //10100
方法3.
String num_s = Integer.toString(20) //调用该类的静态方法 public static String toString(int i) 。
String -> int:
方法1.
Integer i = new Integer("100");
syso(i + 400); //此时i就是一个int类型,结果为500(自动拆箱)
方法2.
Integer i = new Integer("100");
int num = i.intValue(); //调用对象的方法
方法3.
int num = Integer.parseInt("1000"); //这是Integer的静态方法。
推荐:
int -> String : num + ""
String -> int: Integer.parseInt(s)
自动装箱与自动拆箱:
装箱:基本数据类型变成包装类对象。
拆箱:相反
自动装箱应用场景:
Integer i = 10; //将10这个基本数据类型转化成对象
ArrayList list = new ArrayList();
list.add(1) ; //集合只能装对象,这里的1被自动装成对象
自动拆箱应用场景:
Integer i = 10;
int num = i; //这里i被自动拆成基本数据类型,然后由基本数据类型接收
18-11-4:注释、变量、命名、转化.txt****
Java基础
·java跨平台:因为在不同的操作系统上有不同的jvm
jre:运行环境(包括jvm和核心类库)
jdk:开发工具(包括了jre)
·注释:
// 单行注释
/* */ 多行注释
/** **/文档注释
·定义数据类型时的注意:
整形默认是int
浮点默认是double
定义long时数字后加L
定义float时数字后加F
·命名规则:
包:一定要小写,多级包用.分隔
类:首字母大写
方法和变量:首字母小写,后面每个单词首字母大写
·变量的域:
变量的使用,只能在其域中(此变量所在的大括号范围中)
例如
public class Main{
public static void main(String args[]){
{ /*
代码块
*/
int c = 30;
}
System.out.print(c); //无法正常输出
}
}
·类型转换:
一般而言我们要求运算的类型一致
如果不一致就会发生转换:
隐式转换:
byte、short、char -- int -- long -- float -- double (由低向高的转换顺序)
参与运算的数据将自动转换成精度较高的数据,但高精度不可转化为低精度,避免造成缺失数据
例如:
byte a = 10;
int b = 20;
byte x = a + b; //b是int,a将转化成int,最终结果也为int,不可用低精度的变量接收
int y = a + b;
System.out.println(x);
System.out.println(y);
强制转换类型:
强制将高精度转换成低精度,一般不这样做。
例如:
如上
byte x = (byte)(a + b); //这个时候就可以通过编译
18-11-5:字符串加法、双&、随机数、数组.txt****
·字符串参与加法运算
任何类型变量与字符串参与加法运算都是字符串的拼接
System.out.println("a"+100); //a100
System.out.println("a"+'e'); //ae
·&& 与 & 以及 || 与 | 在java中区别不大
但是&&在条件判断中如果前者为false后者不进行判断,而&无论如何两边都会去进行判断
·随机数
用 ctrl + shift + o 快捷键导包
import java.util.Random;
Random r = new Random();
r.nextInt(100); //[0,100) 的随机数
·数组
基本使用
int arr[] = new int[10]; //数组的初始化
System.out.println(arr); //打印的是地址值
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]); //每一个对象进行初始化时都有一个默认值,int的默认值是0
}
静态初始化:
int[] a = {1,2,3};
for(int e: a){ //类似于python的遍历
System.out.println(e);
}
将数组赋值给数组
int[] a1 = new int[3];
int[] a2 = new int[10];
for(int i = 0; i < a1.length; i++){ //对a1数组赋值
a1[i] = i;
}
a2 = a1;
System.out.println(a2.length); //尽管a2分配了10个空间,但a2这个变量指向了a1这个变量的地址,故a2的长度也变成了3
for(int i = 0; i < a2.length; i++){
a2[i] = 100 + i; //对a2进行赋值
}
for(int i = 0; i < a2.length; i++){
System.out.println(a1[i]); //发现对a2的赋值影响到了a1
}
数组内存分配
变量名放于栈中:
int[] arr
对象放于堆中,每个对象都有默认值:
new int[100]
遍历二维数组:
int[][] a = {{1,2,3},{4,5,6},{7,8,9}};
for(int i = 0; i < a.length; i++){
for(int j = 0; j < a[i].length; j++){ //a[i]也是个数组
System.out.print(a[i][j] + " ");
}
System.out.println();
}
18-11-6:方法定义格式、方法重载、以及注意事项、方法参数是基本类型.txt****
·方法:
定义在主类当中
格式:记住格式!
public static int fun(int a, int b){
}
方法重载:
定义:
同一个类中出现了名字相同的方法参数
特点:
同名方法参数个数不一样
同名方法参数类型不一样
如果不满足以上两点:
则报错
注意:
方法重载只比较参数,即只比较参数的个数和类型。对于参数的名字和方法返回类型不予考虑。
整数默认是int,小数默认是double:
例如:
public static void main(String[] args) {
System.out.println(fun(12.0,13.0)); //由于默认小数是double,所以调用double方法
}
public static boolean fun(double a, double b){
System.out.println("double");
return a == b;
}
public static boolean fun(float a, float b){
System.out.println("float");
return a == b;
}
如果想要调用float方法,要么在小数前加转化类型,要么在小数后加f
如果方法的参数是基本数据类型:
则方法对变量的操作不影响实参
例如:
change(a,b) //a还是a,b还是b,不会交换
18-11-8:方法参数是引用类型、断点调试、面向对象格式、初始化值问题、内存分配(重点).txt****
·如果方法的参数的类型引用型参数,方法会影响该引用型变量
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
change(arr); //将arr作为参数传进去
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]); //此时数组的元素全部乘了2
}
}
public static void change(int[] a){
for(int i = 0; i < a.length; i++){
a[i] *= 2;
}
}
·断点
基本操作和Dev C++ 一样
·面向对象:
类中的方法定义:
public int fun(..) // 去掉主类中的static
类中的属性可以不用设值,原因请参考"初始化值的问题"
.初始化值的问题:
在java中数组在定义时每个元素有初始化值;
构建类时,每个属性也有初始化值;
除了数组和类以外,其他所定义的任何变量都没有初始化值。
例如:
int i;
String s;
syso(i);
syso(s); //都是The local variable 变量名 may not have been initialized
原因分析:
如果定义一个基本数据类型,它们是放在栈中,值也保存在栈中,没有赋予初始值,要使用前必须赋值。
而数组和对象是new出来的,它们保存在堆中,堆内存一开始就为它们赋予了初始值
JAVA变量内存分配:
方法区:
javac编译后的 字节码文件 都放在 方法区 中,每个字节码文件就是一个类(这也是为什么类名要和文件名一致)。
方法 和 属性 也在方法区中的 字节码文件 。
栈:
当 调用某方法 时就会将方法 加载到栈 中,方法中的变量也会加载到栈中。
如果这些变量是 基本数据类型,其值和变量一起放在栈中。而且变量 没有初始值 。
如果是 引用类型,其引用变量和其对象的 地址 也一起放在栈中, 指向堆 中的具体对象。
如果栈中的方法执行完,其分配的内存就自动被垃圾回收机制回收。
堆:
如果是new出来的引用数据,就放在堆中。
堆中对象的属性一般是基本数据类型,且都有初值。
堆中存储对象的方法只是 存储其在方法区的地址 。
18-12-10:多异常处理顺序、finally、IO流标准处理异常格式、异常分类、自定义异常(代码)、异常总结.txt****
多个异常的处理:
允许处理多个异常,平级异常次序不重要。
有子父级关系的话:子异常一定放在父异常前面。(如果父异常在前,那么就轮不到子异常处理,编译都通过不了)。
finally–不管try…catch处理异常是否成功,finally中一定执行。
例如:
try {
System.out.println(5 / 0);
}
catch(NullPointerException e) { //上面的异常无法捕获到。
System.out.println("空指针");
}
finally {
System.out.println("释放资源");
}
结果:
释放资源 //即使try..catch没有处理成功,但finally一定执行。
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.异常处理.TryCatchDemo.main(TryCatchDemo.java:11)
IO流的异常处理格式(标准格式):
FileWriter fw = null; //将fw对象初始化,防止空指针异常,以后也一定写成这种样子。
try {
fw = new FileWriter("a.txt");
fw.write("aaaaa");
}
catch (IOException e) {
System.out.println("出现IO流异常");
}
catch (Exception e) {
System.out.println("出现其他异常");
}
finally {
try {
if(fw != null) { //fw非空才将其关闭。
fw.close();
}
}
catch (Exception e) {
System.out.println("关闭时发生异常");
}
}
异常的分类:
运行时期异常:可以不处理,且一定是java.lang.RuntimeException的子类。
编译时期异常:写完必须处理,否则系统不准运行。非java.lang.RuntimeException的子类。
throw 与 throws:
throw是一种制造异常的方式。
throws是一种处理异常的方式,是无法处理异常然后抛出去给调用者处理的方式。
自定义异常:
定义编译异常:只要继承Exception,然后写好构造方法就可以了。
定义运行异常:只要继承RunTimeException然后写好构造方法就可以了。
自定义异常的例子(定义一个编译时期异常):
MyException.java
能够产生异常对象的类
public class MyException extends Exception {
各种构造方法...
}
Demo.java
public class Demo {
public static void main(String[] args) {
try {
checkScore(111); //由于定义的是编译时期异常,要么处理,要么抛给虚拟机,总之一定要处理
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
//此方法用于决定是否生成异常对象。如果满足条件则抛出异常。
public static void checkScore(int score) throws MyException { //由于可能会产生异常,所以一定要在方法后面加上抛出哪种异常的可能。
if(score > 100 || score < 0) {
throw new MyException("成绩异常"); //如果抛出异常代表着方法的结束
}
System.out.println("成绩正常"); //如果没有抛出,则方法会一直执行到这。
}
}
结果: 成绩异常
总结:
1.不管try..catch处理异常是否成功,finally中一定执行。
2.FileWriter fw = null; 以后声明对象时一定设置为null。
3.如果抛出异常,其所在的方法名后一定要加上"throws 异常类型"!!这是为了告诉虚拟机此方法可能会抛出xx异常。
4.如果抛出运行异常,可以不用在方法后面throws,但是最好加上!!
5.如果一个方法throws 编译异常,不管该方法是否有无throw异常,调用此方法时一定要进行处理!一定要处理!
6.方法中如果抛出了异常(throw),则该方法就结束了。
7.父异常要后catch
18-12-12:File类的概述、构造方法、创建、删除、获取、修改、判断功能.txt****
File类的使用:
概述:
File可创建一个指向文件或者文件夹路径的对象,并可以进行一系列操作。
构造方法:(注意:该文件或者文件夹不一定存在)
File(File parent, String child)
parent是一个文件夹的file对象,child是文件名称
File(String pathname)
一个文件或者文件夹的绝对路径
File(String parent, String child)
parent是文件夹路径,child是文件的名称
创建功能:
boolean createNewFile()
创建文件
boolean mkdir()
只能在已经存在的目录中创建创建文件夹。
boolean mkdirs()
可以在不存在的目录中创建文件夹。
删除功能:
boolean delete()
可以删除文件或者文件夹,但如果文件夹下有子文件或子文件夹,则无法删除。(安全起见)
判断功能:
boolean isAbsolute()
测试此抽象路径名是否为绝对路径名。
boolean isDirectory()
测试此抽象路径名表示的文件是否是一个目录。
boolean isFile()
测试此抽象路径名表示的文件是否是一个标准文件。
boolean exists()
测试此抽象路径名表示的文件或目录是否存在。
boolean isHidden()
测试此抽象路径名指定的文件是否是一个隐藏文件。
获取和修改功能:
File getAbsoluteFile()
返回此抽象路径名的绝对路径名形式。
String getAbsolutePath()
返回此抽象路径名的绝对路径名字符串。
String getName()
返回由此抽象路径名表示的文件或目录的名称。
String getParent()
返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
File getParentFile()
返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。
String getPath()
将此抽象路径名转换为一个路径名字符串。
boolean renameTo(File dest)
重新命名此抽象路径名表示的文件。
String[] list()
返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中的文件和目录。
File[] listFiles()
返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。
18-12-13:IO流分类、用字节流进行图片复制、提一下标准输入出流、以后采用数组复制方式.txt****
IO流高级:
IO流分类(按数据类型):
字节流:
字节输入流: InputStream
字节输出流: OutputStream
字符流:
字符输入流: Reader
字符输出流: Writer
用字节流复制图片:
public static void Chars() throws FileNotFoundException, IOException {
//创建对象
FileInputStream fis = new FileInputStream("C:\\Users\\熊汝成\\Pictures\\Saved Pictures\\timg .jpg");
FileOutputStream fos = new FileOutputStream("裴秀智.jpg");
byte[] bs = new byte[1024];
int len;
while ((len = fis.read(bs)) != -1) {
fos.write(bs, 0, len);
}
fis.close();
fos.close();
System.out.println("成功");
}
注意点:
1.字节流不需要flush,字符流才需要flush。
2.以后用数组方式进行复制,高效。
标准输入输出流:
System.in 标准输入流:用于录下键盘中输入的数据
System.out 标准输出流:用在在终端中输出数据
18-12-16:isr与osw的介绍、字符流的操作,字节流的功能.txt****
1.OutputStreamWriter的引用–问题:将数据输出到终端
//输入流对象建立
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//标准输出流对象的建立
OutputStream os = System.out; //多态
String line;
while ((line = br.readLine()) != null) {
os.write(line.getBytes()); //必须将字符串转化成字节流数组才可以
os.write("\n".getBytes());
}
br.close();
os.close();
从上可以看出,当使用OutputStream写入必须是字节或字节数组,现在不想将字符串传换成字节数组。引入OSW
------------------------------------------------------------------------------------
改进源码
//输入流对象建立
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//标准输出流对象的建立
OutputStreamWriter osw = new OutputStreamWriter(System.out);
String line;
while ((line = br.readLine()) != null) {
osw.write(line); //像字符流一样的操作了
osw.write("\n");
}
br.close();
osw.close();
2.终端写入数据:
InputStream is = System.in;
FileWriter fw = new FileWriter("abc.txt");
byte[] bs = new byte[1024];
int len;
while ((len = is.read(bs)) != -1) { //is只能读字节数组
fw.write(new String(bs,0,len)); //把字节数组转化成字符串
fw.flush();
}
is.close();
fw.close();
-----------------------------------------
改进:
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
FileWriter fw = new FileWriter("abc.txt");
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
fw.write(chs,0,len);
fw.flush();
}
is.close();
fw.close();
总结:
InputStreamReader和OutputStreamWriter还是字符流,是包装了字节流的字符流!
他们构造方法中传入字节流对象,然后操作上就是字符流的操作。
这样做到了"字节流的功能,字符流的操作"
18-12-18:字符打印流的概述.txt****
打印流PrintWriter:
概述:
同FileWriter一样,也可以对文件进行写入字符流数据。
复制文本:
BufferedReader br = new BufferedReader(new FileReader("abc.txt"));
//pw的构造方法很多,此构造方法是为了打开自动刷新的功能
PrintWriter pw = new PrintWriter(new FileWriter("D:\\abc.txt"), true);
String line;
while ((line = br.readLine()) != null) {
pw.println(line);
}
/*
* 即使没有刷新,没有关闭文件,同样也能进行自动刷新和换行。
*/
18-12-18:对象操作流的使用.txt****
对象操作流:
概述:可以将对象输入到文件当中。
ObjectInputStream:
构造方法:传入一个InputSteam及其子类的对象。
读取对象的方法:ois.readObject() 抛出编译异常ClassNotFoundException(如果这个对象的类找不到了)
读取文本对象的方法:
方法一:如果文件中全是对象
try {
while (true) {
Object o = ois.readObject();
System.out.println(o);
}
} catch (EOFException e) {
System.out.println("文件读完");
}
方法二:如果文件中是一个集合
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student student : list) {
System.out.println(student);
}
ObjectOutputStream:
构造方法:传入一个OutputSteam及其子类的对象。
写入对象的方法:oos.wirte()
注意:
1.构造方法一定是传入一个字节输入流或者字节输出流。
2.写入的对象一定要实现Serializable这个接口。
18-12-19:IO流的大总结.txt****
IO流的总结:
File:是指向文件或者文件夹路径的一个对象。
知识点:
构造方法、创建、删除、获取、判断、修改等功能。
FileInputStream、FileOutputStream:对文件的读写(以字节为单位)
知识点:
构造方法:
传入File对象或者String(传入String其实是自动创建File对象)
主要方法:
int read()---返回数字。
int read(byte[] b)---将字节流存到byte数组中。
void write(byte[] b, int off, int len) ---将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
void write(int b)--- 将指定字节写入此文件输出流。
注意要点:
不管是读还是写,都是以字节byte为单位。
写入数据不需要flush刷新。
FileReader、FileWriter:对文件的读写(以字符为单位)
注意要点:
大部分知识点和fis、fos一样。
写可以写入各种数据类型(String、int、char...),但读写都是以char为基本单位。
写入数据需要flush刷新。
InputStreamReader、OutputStreamWriter:字节流的功能字符流的操作
知识点:
构造方法:
传入InputStream、OutputStream子类的对象。
注意要点:
该类的方法同Reader、Writer的操作是一样的。它是将字节流的能力包装成字符流的操作。
PrintWriter:打印流
知识点:
构造方法:
传入File、Writer、OutputStream都可以
注意要点:
其实同FileWriter类似,不过他有自动刷新和自动换行的功能。
BufferedWriter、BufferedReader:缓冲流
知识点:
构造方法:
传入Reader、Writer对象。
注意要点:
能够更加高效的处理字符流。
可以读取一行和独特的换行功能。
ObjectInputStream、ObjectOutputStream:对象操作流
知识点:
构造方法:
传入InputStream、OutputStream对象
主要方法:
readObject() 抛出编译异常ClassNotFoundException ,读完所有对象会抛出EOFException
writeObject() 写入对象
注意要点:
加入的对象的类必须实现接口Serializable
总而言之:
1.fis,fos,fw,fr的构造方法都是传入File对象。主要方法是read和write,写的单位是byte和char。字节不刷新字符要刷新。
2.br和bw把fr与fw包装进去,能够提供高效。newLine和readLine是独特方法。
3.对象操作流的构造方法是传入字节流(一般是FileInputStream和FileOutputStream),加入的对象一定要实现接口。读对象可能
找不到类所以抛出一个编译异常,读完文件会抛出一个运行异常。
18-12-20:Properties与IO流的结合.txt****
Properties与IO流的结合: 有种专门的文件是 xxx.properties
Properties的概述:
类似于Map,但键值对只能是String。被称为属性列表。
基本功能:
存数据:
setProperty(String key, String value)
拿数据:
getProperty(String key)
遍历数据:
Set<String> stringPropertyNames() 可以获取所有的键集
源码演示:
//创建Properties对象
Properties pro = new Properties();
//存入数据
pro.setProperty("001", "xrc");
pro.setProperty("002", "lw");
//遍历
Set<String> keys = pro.stringPropertyNames(); //获取到了所有的键。
for (String key : keys) {
String value = pro.getProperty(key);
System.out.println(key + "=" + value);
}
-------------------------------------------------------------------------------------------------
与IO流的结合:
具体方法:
写出数据:
void store(OutputStream out, String comments)
void store(Writer writer, String comments)
读入数据:
void load(InputStream inStream)
void load(Reader reader)
源码演示:
/*
* 将属性列表放入到文件当中
*
*/
//创建属性列表对象
Properties prop = new Properties();
//创建输出流对象
FileWriter fw = new FileWriter(new File("学生"));
//添加键值对关系
prop.setProperty("001", "熊汝成");
prop.setProperty("002", "刘威");
prop.setProperty("003", "周玄");
//将关系存放到文件当中
prop.store(fw, "存放学生对象");
//释放资源
fw.close();
===========================================
/*
* 将文件中的关系读入到属性列表中
*/
//创建一个空的属性列表
Properties prop = new Properties();
//创建输入流对象
FileReader fr = new FileReader(new File("学生"));
//从文件中读取数据
prop.load(fr);
//释放资源
fr.close();
//遍历属性列表,看是否加载成功
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key+"="+value);
}
18-12-20:关于固定序列化ID的必要性.txt****
关于序列化接口ID的问题:
存入一个学生对象后,对学生类进行了修改。在进行读入的时候,就会抛出java.io.InvalidClassException异常。
原因:将学生类写好并实现序列化接口后则系统会分配一个默认的序列化ID,且每次对学生类进行修改后则序列化ID会改变。
当进行读学生操作的时候,发现读的学生类型的序列化ID和现有学生类型的序列化ID不同时,则抛出异常。
措施:在学生类写好并实现了序列化接口以后,则立马固定住序列化ID,这样无论怎么修改,ID不变。就不会抛出错误。
直接在Student类中写一个成员变量 private static final long serialVersionUID = 8846915965544563304L;
18-12-22:Map和List都实现了序列化接口、关闭最外层stream或er便可。.txt****
1.JAVA中的Map、List都是实现了序列化接口,都可以将其存到文件当中。
2.JAVA的IO包下的stream和er都是装饰者模式,只需要调用最外层的close方法就能将内部的stream或er一并关闭。
18-12-26:多线程的概述、多线程的第一种实现方式.txt****
多线程的概述:
进程:可以理解为一个程序。
单线程:一个进程中只做一件事情。安全,效率低。
多线程:一个进程中做多个事情。不安全,效率高。
执行多线程的步骤:
1.创建类并继承Thread
2.将要执行的代码放在void run()中。
3.在主方法中创建对象。
4.调用对象的start方法,该方法会自动执行run中的代码。
代码如下:
主类:
public class ThreadDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
HerThread ht = new HerThread();
mt.start();
ht.start();
}
}
---------------------------------------------------
线程类:
public class MyThread extends Thread {
public MyThread(){
setName("熊汝成");
}
@Override
public void run() {
for (int i = 1; i < 3 ; i++) {
System.out.println("这是"+getName()+
"的第"+i+"个线程!");
}
}
}
class HerThread extends Thread {
public HerThread() {
setName("李育霖");
}
@Override
public void run() {
for (int i = 1; i < 3; i++) {
System.out.println("这是"+getName()+
"的第"+i+"个线程!");
}
}
}
结果:不唯一。
这是李育霖的第1个线程!
这是熊汝成的第1个线程!
这是熊汝成的第2个线程!
这是李育霖的第2个线程!
18-12-26:有关异常中空指针问题、学生管理系统中常出现EOF解决.txt****
关于JAVA的try中的问题:
try {
FileReader fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
fr.close(); //此时fr会亮红线
Java严格讲究代码块的域,出了域绝对找不到变量。fr是一个放在try的代码块中,fr.close()自然
找不到fr变量。修改方式:
FileReader fr = null;
try {
fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
fr.close(); //但会抛出运行异常java.lang.NullPointerException
fr首先是个null,try中的赋值语句没有成功,所以fr一直是null,修改:
FileReader fr = null;
try {
fr = new FileReader("meiyou.txt");
} catch (FileNotFoundException e) {
System.out.println("没有此文件");
}
if (fr != null){
fr.close();
} //这样才是正确的方式。
在写学生管理系统的时候,如果"学生.txt"是一个空文件,在构造ObjectInputStream对象时就会报EOF异常。
看看我是如何排错的:
ObjectInputStream ois = null; //先设立为null
try {
ois = new ObjectInputStream(new FileInputStream("学生")); //尝试下创立ois对象
} catch (EOFException e) {
HashMap<String, Student> map = new HashMap<String, Student>(); //如果报错就添加一个空map进去
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("学生"));
oos.writeObject(map);
oos.close();
ois = new ObjectInputStream(new FileInputStream("学生")); //再创立一次ois对象
}
18-12-2:容器中元素的遍历(转化数组、迭代器)、迭代器中的并发异常、修改迭代器中的元素也会修改原容器中的元素.txt****
元素的遍历:
方法一:转化成object数组,再进行遍历。
//方法一,转化成数组进行遍历
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("xiongrucheng");
Object[] os = c.toArray();
for(int i = 0; i < os.length; i++){
System.out.println(os[i]);
}
方法二:转化成迭代器对象,进行遍历:
Collection c = new ArrayList();
c.add("hello");
c.add("java");
c.add("xiongrucheng");
Iterator it = c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
解决迭代器中的并发异常:
由于迭代器是集合的副本,必须与集合相一致。
如果迭代器中的元素没有变,但集合中的元素发生改变就会造成:Exception in thread "main" java.util.ConcurrentModificationException(并发修改异常)
如果集合中的元素没有变,修改迭代器,迭代器会影响集合的变化。
//声明一个List对象
List list = new ArrayList();
//添加三个元素
list.add("hello");
list.add("java");
list.add("xiongrucheng");
//调用list.listIterator() 制造一个列表迭代器,因为列表迭代器拥有add方法
ListIterator itor = list.listIterator();
System.out.println(list); //结果:[hello, java, xiongrucheng]
while(itor.hasNext()){
String s = (String)itor.next(); //itor.next()转化一个String对象,向下转型
if(s.equals("java")){
itor.add("python"); //注意,如果是list.add("python")会引发异常,所以是迭代器中添加元素
}
}
System.out.println(list); //[hello, java, python, xiongrucheng]
//迭代器的变化造成了原集合的变化
迭代器可以对原集合进行永久改变:
LinkedList<Student> list = new LinkedList<Student>();
//添加元素
list.add(new Student("熊汝成", 19));
list.add(new Student("刘威", 18));
list.add(new Student("李凯文", 20));
//通过迭代器进行修改,通过迭代器,将每一个元素的名字和年龄修改
Iterator<Student> itor = list.iterator();
while(itor.hasNext()){
Student s = itor.next();
s.setAge(0);
s.setName("无名氏");
}
//在进行遍历原列表
for (Student student : list) {
System.out.println(student);
}
结果:
Student [name=无名氏, age=0]
Student [name=无名氏, age=0]
Student [name=无名氏, age=0] //发现利用迭代器进行操作了以后,原集合也都改变了。
18-12-2:泛型和增强for循环.txt****
泛型:
在java的集合类中,有许许多多的泛型。
因为集合可以添加任何类型元素,泛型可以将集合像数组一样,规定添加元素的类型。
增强for循环:
for(ElemType e : 集合对象){
}
18-12-3:List中的增删查改、元素是对象时的排序(附加源码)、foreach的修改元素.txt****
List对象中的操作:
初始化: List<Student> mylist = new LinkedList<Student>();
//其实增删查改同ArrayList一样。
添加:
mylist.add();
删除:
mylist.remove();
查找:
mylist.get()
修改:
mylist.set()
排序:
Collections.sort(列表)
注意:
1.列表中的元素的类型(比如Student),一定要实现Compareble,且重写 int compareTo(E o)方法。
2.返回值是一个整形,是自己的属性与对方的属性的差值。
对于ArrayList,上述也是如此。
具体用ArrayList还是LinkedList,取决于你是增删多,还是查改多。
foreach对于元素是基本数据类型的数组修改无效,对于元素是引用类型的数组修改有效.
例如:
for (Student student : list) {
student.name = "hhh"; //list中的元素是引用数据类型,foreach修改成功
}
for(int i : intArray){
i = 20; //intArray中的元素是int,foreach不可修改
}
源码:
Demo.java
package com.sort_and_find;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<Student> list = new LinkedList<Student>();
//添加学生
list.add(new Student(1709301, "zw", 108));
list.add(new Student(1709305, "xrc", 19));
list.add(new Student(1709302, "laowang", 50));
//先输出学生
for (Student student : list) {
System.out.println(student.schoolnumber+"-"+student.name+
"-"+student.age);
}
System.out.println("------------");
//排序
Collections.sort(list);
//再输出,利用迭代器
Iterator<Student> itor = list.iterator(); //注意,迭代器也要指定泛型
while(itor.hasNext()){
Student student = itor.next();
System.out.println(student.schoolnumber+"-"+student.name+
"-"+student.age);
}
//利用二分法来查找
/*
* 利用二分法,首先要排好序
* 其次,查找是根据Student中compareTo方法比较的何种属性进行查找的
*/
int index = Collections.binarySearch(list, new Student(1709302,"laowang",108));
System.out.println(index);
}
}
Student.java
package com.sort_and_find;
public class Student implements Comparable{
int schoolnumber;
String name;
int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int schoolnumber, String name, int age) {
super();
this.schoolnumber = schoolnumber;
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
// TODO Auto-generated method stub
return this.age - o.age; //根据年龄比较
}
}
结果:
1709301-zw-108
1709305-xrc-19
1709302-laowang-50
1709305-xrc-19
1709302-laowang-50
1709301-zw-108 //根据年龄排序
2 //只能根据年龄进行查找
18-12-4:collections工具类中对容器的洗牌与旋转.txt****
洗牌与旋转:
Collections提供了以下方法:
洗牌:public static void shuffle(List<E>list) 可以将数据重新排列。
旋转:public static void rotate(List<E>list, int distance)
逆转:public static void reverse(List<E> list)
18-12-4:有关HashMap的相关操作,特别是遍历.txt****
散列映射(字典)的基本操作:
1.初始化:
HashMap<String, Student> map = new HashMap<String, Student>();
2.添加元素:
map.put("xiongrucheng", new Student("熊汝成", 19));
3.输出map中的元素个数
syso(map.size())
4.根据键来查询元素
Student s = map.get("xiongrucheng");
System.out.println(s); //结果:Student [name=熊汝成, age=19]
5.查询是否包含该键:
System.out.println(map.containsKey("xiongrucheng")); //结果:true
6查询是否包含该值:
System.out.println(map.containsValue(new Student("威威", 50))); //结果,false,因为两对象地址不同
7.移除:
map.remove("likaiwen");
8.遍历:
//map.values()将返回一个实现了Collection<Student>接口类创建的对象。个人理解应该是返回了一个实现了Collection的
//匿名内部类的对象。并将该对象赋值给接口变量。
Collection<Student> c = map.values();
//c因为实现了接口的方法,所以可以返回一个确确实实的迭代器。
Iterator<Student> itor = c.iterator();
//遍历迭代器
while(itor.hasNext()){
System.out.println(itor.next());
}
//当然,也可以用foreach来遍历这个对象
Collection<Student> values = map.values();
for (Student student : values) {
System.out.println(student);
}
9.清空:
map.clear();
10.键值对的遍历:
上面的8是对键或者对值的单独遍历,现在讨论键值对的遍历
方法一:
public static void Method1(Map<String, String> map) {
//通过对键的遍历,一个个的遍历Map
Set<String> keys = map.keySet();
for (String key : keys) {
String value = map.get(key);
System.out.println(key + "--" + value);
}
}
方法二:
//利用Map中的内部类进行遍历
public static void Method2(Map<String, String> map) {
Set<Map.Entry<String,String>> entrys = map.entrySet(); //Map.Entry是Map中的内部类
for (Map.Entry<String, String> entry : entrys) {
System.out.println(entry.getKey()+"--"+entry.getValue());
}
}
注意点:
如何通过键进行对值的修改?
只需要重新put()就可以进行覆盖修改了
18-12-4:栈的基本操作.txt****
栈堆:
boolean empty()
测试堆栈是否为空。
E peek()
查看堆栈顶部的对象,但不从堆栈中移除它。
E pop()
移除堆栈顶部的对象,并作为此函数的值返回该对象。
E push(E item)
把项压入堆栈顶部。
int search(Object o)
返回对象在堆栈中的位置,以 1 为基数。
18-12-5:List中的排序(详解),Comparable与Comparator的区别(内外比较器的比较)、学生集合各个属性排序(完整代码).txt****
List中的排序问题:
1.对于基本数据类型:
正序
Collections.sort(list);
逆序
Collections.sort(list,new Comparator<Integer>(){ //实现一个Comparator的内部类对象
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
2.对于引用数据类型的排序:
方法一:利用匿名类实现Comparator<Student>接口
Collections.sort(list,new Comparator<Student>(){
@Override
public int compare(Student o1, Student o2) {
return o1.getRank() - o2.getRank(); //根据名字排序:return s1.getName().compareTo(s2.getName());
}
});
方法二:Student类中实现Comparable<Student>接口
类:public class Student implements Comparable<Student>{...}
重写方法:
@Override
public int compareTo(Student o) {
return o.rank - this.rank;
}
Comparable 与 Comparator的区别:
内比较器:Comparable形容词,表示可比较的。这种接口往往是需要类去实现的,从而增加类的一个“可比较”功能。
外比较器:Comparator表示比较器,一般是通过内部类实现该接口的功能,用于给Collections.sort()传递参数。一般推荐这种方式。
对学生的各个属性排序的完整代码:
package com.sort_and_find;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class SuperDataDemo{
/*
*静态的成员内部类
*/
static class sortByName implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getName().compareTo(o2.getName());
}
}
static class sortByAge implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
static class sortByRank implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getRank() - o2.getRank();
}
}
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
//添加学生
list.add(new Student("jack", 45, 'a'));
list.add(new Student("beak", 20, 'c'));
list.add(new Student("tom", 90, 'f'));
list.add(new Student("keven", 31, 't'));
list.add(new Student("anny", 8, 'e'));
//遍历
for (Student student : list) {
System.out.print(student);
}
System.out.println();
//排序,根据xx来排序
Collections.sort(list, new sortByRank());
//遍历
for (Student student : list) {
System.out.print(student);
}
System.out.println();
}
}
18-12-9:异常的处理、抛出(初步,后续还有补充).txt****
异常处理:
1.异常体系:
超类:java.lang.Throwable--->java.lang.Error(不可扭转的的错误), java.lang.Exception(可处理的异常)
2.异常处理的方式:
捕获并处理异常
抛出异常
3.捕获并处理异常try..catch语句:
格式:
try{
可能发生异常的语句
} catch(异常类型 e){
处理语句
}
注意点:
1.发生异常后,如果没有try..catch语句,则jvm会自动关闭程序。
2.如果写了语句,发生异常后自动跳转到catch中,不会再跳回try语句中。例如:
代码:
try{
System.out.println("try的第一条");
System.out.println(4/ 0);
System.out.println("try的第二条"); //跳转到catch中,不会再回来
} catch(Exception e){
System.out.println("发生异常");
}
结果:
try的第一条
发生异常
4.抛出异常:
异常都是发生在某个方法当中,如果没能力处理或者不想处理该异常,就可以将异常抛出去,交给调用方法的人去处理。
格式:
方法名() throws 异常类型{} //注意,异常类型可以写此异常类型的父类型。
抛出异常还遗留许多问题,见后续补充
19-1-10:TCP通信的补充点.txt****
TCP协议进行数据通信的注意点:
1.
输入流--------------相互连接--------------输出流
| |
| |
| |
客户端Socket 服务端Socket
| |
| |
| |
输出流--------------相互连接---------------输入流
如图所示,客户端的Socket与服务端accept后的Socket的交错连接。
调用getInetAddress()方法获取的是对方的IP对象。
2.Java的socket是一个全双工套接字,任何的输入流或输出流的close()都会造成Socket关闭。
所以,不要用close方法关闭socket的IO流,可以用shutdown方法。
19-1-13:单元测试Junit.txt****
Junit单元测试:
在主类中的方法中添加注解@Test、@After、@Before便可进行单元测试,且方法不可是静态方法。
19-1-5:InetAddress类的简要了解.txt****
InetAddress类的介绍:
概述:此类表示互联网协议 (IP) 地址。
初始化方法:
static InetAddress getByName(String host)
在给定主机名的情况下确定主机的 IP 地址。 host可以是主机名,也可以是ip地址。
获取方法:
String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
String getHostName()
获取此 IP 地址的主机名。
static InetAddress getLocalHost()
返回本地主机。
19-1-5:主方法的运行是单线程的、多线程的第二种实现方法.txt****
主方法是单线程的,在主方法中调用各种方法时,程序是从上往下,从左往右运行。
实现多线程的第二种方式:
1.创建一个类实现接口Runnable,并重写run方法。
2.在主方法创建类实例mt。
3.在主方法中创建Thread实例t,并将mt对象传递进去。
4.调用start方法,开启线程.
代码如下:
主类:
public class ThreadDemo {
public static void main(String[] args) {
//创建MyThread对象
MyThread mt = new MyThread();
//创建第一个Thread对象,将mt传进去。
Thread t = new Thread(mt);
t.setName("老王");
//创建第二个Thread对象,将mt传进去
Thread t2 = new Thread(mt);
t2.setName("老张");
t.start();
t2.start();
}
}
自定义类:
public class MyThread implements Runnable {
@Override
public void run() {
for (int i = 1; i < 4; i++) {
System.out.println(Thread.currentThread().getName() + //静态的获取当前线程的方法
"的" + i + "个线程");
}
}
运行结果:
老张的1个线程
老王的1个线程
老王的2个线程
老王的3个线程
老张的2个线程
老张的3个线程
第二种方法的意义:
第一种方法是继承,第二种方法是实现,二解决了一的多继承问题。
19-1-5:利用同步代码块或同步方法解决多线程中的并发问题.txt****
多线程可能遇到的问题:
当有多个线程。
多个线程共享一个数据源。
就有可能会造成数据重复执行等问题。
为了解决这个问题,引进同步代码块的概念。
同步代码块:
格式:
synchronized (this) {
每一个线程的运行代码。
}
作用:
当线程的运行代码被synchronized(this){}包住以后,当运行这个线程时,将会开启一个锁,其他线程暂时无法运行。
源码:
public class MyThread implements Runnable {
int count = 100; //票的总数
@Override
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (this) { //需要进行封锁的地方,加上同步代码块
if (this.count > 0) {
System.out.println(Thread.currentThread().getName() +
"第" + this.count + "张票正在出售");
this.count --;
}
}
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
//实例化mt对象.
MyThread mt = new MyThread();
//实例化多线程窗口一
Thread t1 = new Thread(mt);
t1.setName("窗口一");
//实例化多线程窗口二
Thread t2 = new Thread(mt);
t2.setName("窗口二");
//实例化多线程窗口三
Thread t3 = new Thread(mt);
t3.setName("窗口三");
//实例化多线程窗口四
Thread t4 = new Thread(mt);
t4.setName("窗口四");
//启动线程
t1.start();
t2.start();
t3.start();
t4.start();
}
}
同步方法:
将synchronized放在run方法前面作为修饰符修饰,就可以将整个方法锁住。
@Override
public synchronized void run() { ... } //用synchronized修饰后也是重写方法。
19-1-6:利用UDP协议发送并接收数据.txt****
使用UDP协议发送数据:
步骤:
1.创建发送端对象DatagramSocket类的对象。
2.创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
3.发送出去。
4.释放资源
创建发送端对象DatagramSocket类的对象:
使用无参构造,因为发送端不关心端口号。
DatagramSocket ds = new DatagramSocket();
创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
发送数据:
ds.send(dp);
发送端完整程序:
public class UDPSendDemo {
public static void main(String[] args) throws IOException {
//1.创建发送端对象DatagramSocket类的对象。
DatagramSocket ds = new DatagramSocket();
//2.创建数据包对象DatagramPacket类的对象,包含了数据,ip地址,端口号。
String content = "你好,我叫熊汝成";
byte[] bys = content.getBytes(); //将字符串转化成字节数组
int length = bys.length;
InetAddress address = InetAddress.getByName("192.168.190.1"); //创建InetAddress对象。
int port = 8888;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
//3.发送出去。
ds.send(dp);
//4.释放资源
ds.close();
}
}
UDP协议接收数据:
步骤:
1.创建DatagramSocket对象
2.创建Datagrampacket对象,这是一个容器,接收数据要用到
3.接收数据,将数据放在包中。
4.解包,获取包中的各项数据
5.释放资源
创建DatagramSocket对象:
注意,要与发送端的端口号一致。
DatagramSocket ds = new DatagramSocket(8888);
创建Datagrampacket:
使用DatagramPacket(byte[] buf, int length)构造便可,因为只是为了接收数据,创建一个容器便可。
接收数据,将数据放在包中:
ds.receive(dp); //这样就将数据放在了容器dp中。
解包,获取包中的各项数据:
通过dp中的各种get方法得到数据。
完整程序:
public class UDPGetDemo {
public static void main(String[] args) throws IOException {
//1.创建DatagramSocket对象
DatagramSocket ds = new DatagramSocket(8888);
//2.创建Datagrampacket对象,这是一个容器,接收数据要用到
DatagramPacket dp = new DatagramPacket(new byte[1024], 1024);
//3.接收数据,将数据放在包中。
System.out.println("准备接收数据");
ds.receive(dp);
System.out.println("接收到了数据");
//4.解包,获取包中的各项数据
byte[] bys = dp.getData();
InetAddress address = dp.getAddress();
int length = dp.getLength();
String content = new String(bys, 0, length);
System.out.println("sender -->" + address.getHostName());
System.out.println("content -->" + content);
//5.释放资源
ds.close();
}
}
注意:在第75行会有发生堵塞,打开接收端后程序会一直运行,直到收到消息。
19-1-9:利用TCP协议进行数据的发送和接收.txt****
利用TCP协议进行发送数据:
步骤:
1.创建Socket对象
2.从Socket对象中获取输出流对象。
3.利用输出流发送数据
4.释放资源
创建Socket对象:
Socket(InetAddress address, int port) //对方的IP地址和端口号
从Socket对象中获取输出流对象:
OutputStream os = s.getOutputStream();
利用输出流发送数据:
os.write(byte[]);
利用TCP协议进行接收数据:
步骤:
1.创建ServerSocket对象。
2.利用此对象返回一个Socket对象,用于监听(堵塞)
3.获取输入流对象
4.获取数据
5.释放资源
创建ServerSocket对象:
ServerSocket ss = new ServerSocket(9999); //本机端口号
利用此对象返回一个Socket对象,用于监听(堵塞):
Socket s = ss.accept(); //在此处程序堵塞
获取输入流对象:
InputStream is = s.getInputStream();
获取数据:
String sender = s.getInetAddress().getHostAddress() + "--" +
s.getInetAddress().getHostName();
byte[] bys = new byte[1024];
int len;
len = is.read(bys);
String content = new String(bys, 0, len);
System.out.println("sender -->" + sender);
System.out.println("content -->" + content);
释放资源:
s.close();
// ss.close(); //服务端不应该关掉。
2019-1-13:JAVA的类加载机制.txt****
JAVA的类加载机制:
1.加载class文件到内存
2.将加载好的数据融合到jre这个大的环境中。
3.进行一系列初始化的工作