JAVA基础的全集

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.进行一系列初始化的工作
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值