Java4Android学习笔记

来源:互联网 发布:单机游戏 知乎 编辑:程序博客网 时间:2024/04/29 09:20

01_Java考古学

Java4Android课程介绍

什么是Java考古学

Java发展史

总结

02_Java创世纪

书写源代码、编译、运行

在命令行窗口中,通过cd进入所写的java目录(假设所写的java程序为HelloWorld.java),运行

javac HelloWorld.java 进行编译

java HelloWorld 进行运行

03_Java基本概念

1.环境变量通常是指在操作系统当中,用来指定操作系统运行时需要的一些参数

2.环境变量通常为一系列的键值对

3.Path环境变量是操作系统外部命令搜索路径

4.classpath环境变量是类文件搜索路径

5.编译是把源代码翻译成计算机可识别的代码,

6.JRE是JAVA Runtime Environment即Java运行环境

7.编译器是把源文件翻译成虚拟机能识别的代码,JVM(JAVA虚拟机)是把.class类文件翻译成操作系统可识别的代码

04_Java的变量

什么是变量?

1.计算机是一种极度精确的机器;

2.要将信息存储在计算机当中,就必须指明信息存储的位置和所需要的内存空间;

3.在Java编程语言当中,使用声明语句来完成上述的任务;

变量的声明方法:

变量命名需符合驼峰命名法:1、变量名应该用有意义的英文单词;2、变量名如果只有一个单词,则所有的字母小写;3、变量名如果由多个英文单词组成,则从第二个单词开始首字母大写

05_Java的基本数据类型

主要内容:

1.Java数据类型分类

2.boolean类型变量特征

3.char类型变量特征

4.数值型变量特征

1.数据类型分类

2.布尔型变量

    ①boolean类型适用于逻辑运算,一般用于程序流程控制

    ②在Java当中boolean类型只有两种取值可能-----true和false

    eg:

        boolean b = false;

3.字符型变量

    ①char类型变量用于表示通常意义上的字符;

    ②字符是由单引号括起来的单个字符;

    eg:

        char c = 'a';

    Java字符使用Unicode字符集

4.ASCII字符集

    ①在计算机中所有的数据都需要使用二进制的数字表示;

    ②类似于a,b,c无法直接用二进制表示,所以就将所有常见的符号进行编号

    ③标准ASCII码使用7位2进制数来表示字符;

    7位2进制数可以表示所有的数字、大小写字母以及一些常见的符号(例如!,@,#$);

5.Unicode字符集

    Unicode为每种语言的每个字符设定了统一并且唯一的二进制码

    Unicode使用数字0-0x10FFFF来表示字符,最多允许有1114112个字符

    ③乱码的产生是存这个字的字符集跟取这个数的字符集不一样;

    Unicode中一个中文字符跟一个英文字符所占的空间是一样的;

06_练习课(基本数据类型的赋值与运算)

  1. 创建一个Java源文件,命名为Exerc01.java。在主函数当中创建一个boolean类型的变量,并且尝试为这个变量赋值(true,false和0),并将这个变量的值打印出来。

    Exerc01.java

    publicclass Exerc01 {

        publicstaticvoid main(String args []){

            booleanb = true;

            System.out.println(b);

        }

    }

    编译运行

    true

  2. 创建一个Java源文件,命名为Exerc02.java。在主函数中创建一个char类型的变量,并尝试为这个变量赋值(英文字符或者中文字符),并将这个变量的值打印出来。

    Exerc02.java

    publicclass Exerc02 {

        publicstaticvoid main(String args []){

            charc = 'a';

            //char c = '';

            System.out.println(c);

        }

    }

    编译运行

    a

  3. 创建一个Java源文件,命名为Exerc03.java。在主函数中为每一种数值型创建一个变量,并且赋值,然后进行各种加减乘除的运算。

    Exerc03.java

    publicclass Exerc03 {

        publicstaticvoid main(String args []){

            byteb = 0;

            shorts = 0;

            inti = 0;

            longl = 0;

            floatf = 0;

            doubled = 0;

            //float f1 = 0.1; //可能损失精度

            floatf1 = 0.1F;     //正确

            //int j = 0.5*10;    //可能损失精度

            doublej = 0.5*10 + 4 + 1;     //正确

            //byte k = b+0;    //可能损失精度

            bytek = (byte)(b+0); //正确

            

        }

    }

 

字面量:

整数字面量为整型(int)

小数字面量为双精度浮点型(double)

 

07_运算符与表达式

Java当中的运算符

1、算术运算符:+,—,*,%,++,——

2、关系运算符:>,<,>=,<=,==,!=

3、布尔逻辑运算符:!(逻辑非),&(逻辑与),丨(逻辑或),^(逻辑异或),&&(短路与),||(短路或)

4、位运算符:&,丨,^,~,>>,<<,>>>

5、赋值运算符:= 扩展赋值运算符:+=, —=,*=,/=

6、字符串连接运算符:+

算术运算符

要点一:

Int I = 3/2 请问i的值是几?(答案:i=1)

原因:一个运算的结果取决于所有操作数中操作数那个最大的类型。

要点二:

i++和++i的区别是什么?

i++是使用了i的值之后再将i的值加1
++i是在使用i的值之前就将i的值加1

 

 

表达式的类型和值

表达式是符合一定语法规则的运算符和操作符的序列:

如i; 10.5+i; (i+j)-2

表达式的值

对表达式中操作数进行运算得到的结果称为表达式的值

表达式的类型:

表达式的值的数据类型即为表达式的类型

 

08_分支语句

程序运行流程的分类:顺序结构;分支结构;循环结构

 

default用[]括起来表示其在程序中可有可无,实际程序中用到default时不需要[]

09_练习课(二)

练习目标:熟悉if…else…结构的使用方法

练习一:将学生分数按标准分为:优、良、中、差四个级别

步骤:

  1. 创建一个名为Test01的类;
  2. 在Test01类中加入主函数;
  3. 在主函数当中定义一个整型变量,用于表示学生的分数;
  4. 使用if…else…结构对分数进行分级;

Test01.java

publicclass Test01 {

    publicstaticvoid main(String args []){

        intscore = 90;

        if(score > 85 && score <= 100){

            System.out.println("成绩为优");

        }

        elseif(score > 75 && score <=85){

            System.out.println("成绩为良");

        }

        elseif(score > 60 && score <=75){

            System.out.println("成绩为中");

        }        

        elseif(score <= 60){

            System.out.println("成绩为差");

        }

        elseif(score > 100 && score < 0){

            System.out.println("成绩不在正常范围内");

        }

            

    }

}

练习二:猜拳游戏

步骤:

  1. 创建一个名为Test02的类;
  2. 在Test02类当中加入主函数;
  3. 在主函数当中定义两个char类型的变量,分别代表两个玩家的出拳;
  4. 使用if…else…结构对结果进行判断;

Test02.java

publicclass Test02 {

    publicstaticvoid main(String args []){

        //'a'代表石头,'b'代表剪子,'c'代表布

        charplay1 = 'a';

        charplay2 = 'b';

        if(play1 == 'a' && play2 == 'a'){

            System.out.println("");

        }

        elseif(play1 == 'a' && play2 == 'b'){

            System.out.println("play1");

        }

        elseif(play1 == 'a' && play2 == 'c'){

            System.out.println("play2");

        }

        elseif(play1 == 'b' && play2 == 'a'){

            System.out.println("play2");

        }

        elseif(play1 == 'b' && play2 == 'b'){

            System.out.println("");

        }

        elseif(play1 == 'b' && play2 == 'c'){

            System.out.println("play1");

        }

        elseif(play1 == 'c' && play2 == 'a'){

            System.out.println("play1");

        }        

        elseif(play1 == 'c' && play2 == 'b'){

            System.out.println("paly2");

        }

        elseif(play1 == 'c' && play2 == 'c'){

            System.out.println("");

        }

    }

}

10_循环语句

for循环执行过程

forint i = 0; i < 10; i++{

        System.out.println(i);

}

while循环执行过程:

while (i < 10)    {

    System.out.println(i);

    i++

}

11_练习课(三)

目标:熟悉java当中的for循环使用方法

练习一:打印出100——200之间的所有素数

步骤:

1、定义一个类,名为TestPrimNumber;

2、在类当中定义函数;

3、用for循环打印出所有在100——200之间的素数;

    用for循环当中,每当循环执行一次,就判断循环变量的值是否为素数,如果是,就将循环变量的当前值打印出来;

    判断n是否为素数方法:首先用2除n,如果除不尽,再用3除n,一次类推,如果从2到n-1,都无法整除n,那么n就为素数。

TestPrimNumber.java

class TestPrimeNumber{

    publicstaticvoid main(String args []){

        for(inti = 100 ; i < 201 ; i++ ){

            booleanb = false;

            for(intj = 2 ; j < i-1;j++ ){

                intk = i % j;

                if(k ==0){

                    b = true;

                }

            }

            if(!b){

                System.out.println(i);

            }

        }

    }

编译运行

101

103

107

109

113

127

131

137

139

149

151

157

163

167

173

179

181

191

193

197

199

练习二:在命令行中打印出如下的图形:

步骤:

1、定义一个类,名为TestTriangle;

2、在类当中定义一个主函数;

3、使用for循环打印四行,每行一个"*"

打印四行,每一行当中都包含四个"* "

打印四行,第一行当中有一个"* "第二行当中有"* ",一次类推;

在打印"*"之前,首先要打印" "第一行当中首先打印三个" ",第二行两个,一次类推;

TestTriangle.java

class TestTriangle{

    publicstaticvoid main(String args[]){

        for(inti = 1; i < 5 ; i++){

            for(intj = 0 ; j < 4 - i ; j++ ){

                System.out.print(" ");

            }

            for(intk = 0; k < i ; k++){

                System.out.print("* ");

            }

            System.out.println("");

        }

    }

}

注:print如果不加—ln代表不用换行,加—ln代表需要换行,System.out.println("")这语句代表换行

12_面向对象基础(一)

  1. 面向对象是一种编程方法,是一种思维方式,不是一种编程语言
  2. 什么是面向对象思维方法?

    首先确定谁来做,其次确定怎么做;

    首先考虑整体,其次考虑局部;

    首先考虑抽象,其次考虑具体。

总结:不要认为掌握了一门面向对象语言就是掌握了面向对象;习惯于将面向对象与现实世界做比较

13_面向对象基础(二)

1.定义类的方法

class 类名

{

    属性;

    方法;

}

属性也叫成员变量,主要用于描述类的状态;方法也叫成员方法,主要用于描述类的行为。

2.生成对象的方法

格式:类名 对象名=new 类名();

例如:Dog dog=new Dog();

对象的本体放在堆内存中,对象的名在栈内存中    

例如Dog d=new Dog();这行代码的运行过程如下:

Dog d在栈内存中创建了一个Dog的引用;执行new Dog ()创建了一个Dog的对象,而对象本身放在堆内存中,new用来在堆内存中开辟一块空间放真正的对象,执行new Dog()在堆内存中开辟一块空间并将生成的Dog类型的对象放在这块空间里。所以说真正的对象在堆内存中,d只是指向对象的引用。注意:d不是对象,只是代表了对象。

类与对象的关系:类是抽象的概念,对象是具体的个体。

14_面向对象基础(三)

1.对象的使用方法

使用对象调用变量和函数:

  1. 对象.变量
  2. 对象.函数()

     

例如定义Dog类

Dog.java

class Dog{

    String name;

    intage;

    String color;

 

    void jump(){

        System.out.println("jump");

    }

}

然后生成类的对象

Test.java

class Test{

    publicstaticvoid main(String args []){    

        Dog d = new Dog();

        d.name = "旺财";

        d.age = 2;

        d.color = "黑色";

 

        d.jump();

        System.out.println("名字是"+d.name);

    }

}

生成多个对象

Dog d1 = new Dog();

Dog d2 = new Dog();

只要生成对象就会用到new;堆内存中生成对象,栈内存中引用;只要见到new在堆内存中就会生成新对象,查看程序中生成了几个对象就看new出现多少次就行了

Test.java

class Test{

    publicstaticvoid main(String args []){    

        Dog d1= new Dog();

        Dog d2= new Dog();

        d1.name="旺财";;

        d2.name="四喜";

 

        d1.jump();

        d2.jump();

    }

}

修改一个对象例如d1的属性是不会影响d2的属性的

2.匿名对象的使用

    可以不定义对象的引用名称,而直接调用这个对象的方法。这样的对象叫做匿名对象,例如:

        new Dog().jump();

匿名对象都是一次性的对象,因为没有名字,用完就找不到了

15_面向对象基础(四)

1.函数的重载

class A {

    void funA(){

        System.out.println("没有参数的funA函数");

    }

    void funA(inti){

        System.out.println("拥有一个整型参数的funA函数");

    }    

}

这俩函数构成了重载关系:第一这俩函数在同一个类中,第二这俩函数函数名相同,第三参数列表不同。调用哪一个funA关键看传递的参数

重载的定义

  1. 两个或者多个函数在同一个类当中
  2. 函数名相同
  3. 参数列表不同

2.构造函数

class A {

    A(){

        

    }

    void funA(){

        System.out.println("没有参数的funA函数");

    }

    void funA(inti){

        System.out.println("拥有一个整型参数的funA函数");

    }    

}

构造函数特征:没有返回值类型的定义,函数名必须跟类名相同

但是类中没有构造函数为什么也能用构造函数呢?因为编译器在编译源文件时会检查类中是否拥有构造函数,没有的话会自动加一个无参数且方法体为空的构造函数。如果类中已有构造函数,编译器就不会添加参数为空的构造函数。

构造函数作用:使用new调用构造函数可以生成对象;可以自己编写构造函数为成员变量赋初始值

Person.java

publicclass Person {

    Person(){

        

    }

    Person(String n,inta){

        name = n;

        age = a;

    }

    String name;

    intage;

}

Test.java

class Test {

    publicstaticvoid main(String args[]){

        Person person1 = new Person("zhangsan",10);

        Person person2 = new Person("lisi",20);

        System.out.println("person1name"+person1.name+"age"+person1.age);

        System.out.println("person2name"+person2.name+"age"+person2.age);

    }

}

16_this的使用方法

主要内容:

  1. 使用this调用成员变量和成员函数
  2. 使用this调用构造函数

 

用法一:使用this调用成员变量和成员函数

Person.java

class Person {

     String name;

      

     void talk(){

         System.out.println("my name is "+this.name);

     }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person p1 = new Person();

        p1.name = "zhangsan";

        Person p2 = new Person();

        p2.name = "lisi";

        p1.talk();

        p2.talk();

    }

}

运行结果

my name is zhangsan

my name is lisi

 

如下场合this可以省略

     void talk(){

         System.out.println("my name is "+this.name);//此处this可省略

     }

如下场合this不可以省略,函数参数是name,成员变量也叫name

     void talk(String name){

         System.out.println("my name is "+this.name);

}

这里this.namename代表成员变量的name,如果省略this的话代表参数name

this代表了调用函数的那个对象,如p1.talk(),p1调用了talk(),this就代表了p1。就像是中文中的"我"。张三说"我"时,"我"字代表张三;李四说"我"时,"我"代表李四。

用法二:使用this调用构造函数

Person.java

class Person {

     String name;

     intage;

     String address;

    

     Person(){

         System.out.println("无参数的构造函数");

     }

      

     Person(String s1,inta,String s2){

         name = s1;

         age = a;

         address = s2;

     }

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

构造函数这样写没问题,但是调用时容易乱,应该如下写

     Person(String name,intage,String address){

         this.name = name;

         this.age = age;

         this.address = address;

}

this.name代表成员变量,等号后边的name代表参数

现在的构造函数是对Person的三个成员变量都赋值,有的时候只需要对两个成员变量赋值,再定义如下的构造函数能实现功能,但是显得重复了。

 

Person.java

class Person {

     String name;

     intage;

     String address;

      

     Person(){

         System.out.println("无参数的构造函数");

     }

 

     Person(String name,intage){

         this.name = name;

         this.age = age;

     }

      

     Person(String name,intage,String address){

         this.name = name;

         this.age = age;

         this.address = address;

     }

      

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

 

如下写法才是合理的

Person.java

class Person {

     String name;

     intage;

     String address;

      

     Person(){

         System.out.println("无参数的构造函数");

     }

 

     Person(String name,intage){

         this.name = name;

         this.age = age;

     }

      

     Person(String name,intage,String address){

         this(name,age);//在构造函数中调用Person(String name,intage)

         this.address = address;

     }

      

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

一个构造函数中使用this调用另一个构造函数,必须注意的是在一个构造函数this必须是第一条语句,这样的话在一个构造函数里只能调用同类的另一个构造函数,不能调用同类的另两个构造函数,也就是不能有如下写法

class Person {

     String name;

     intage;

     String address;

     Person(){

         System.out.println("无参数的构造函数");

     }

 

     Person(String name,intage){

         this.name = name;

         this.age = age;

         System.out.println("两个参数的构造函数");

     }

      

     Person(String name,intage,String address){

         this();

         this(name,age);

         this.address = address;

         System.out.println("三个参数的构造函数");

     }

      

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

如果非得调用另外两个构造函数的话可以如下写法

class Person {

     String name;

     intage;

     String address;

      

     Person(){

         System.out.println("无参数的构造函数");

     }

     Person(String name,intage){

         this();

         this.name = name;

         this.age = age;

         System.out.println("两个参数的构造函数");

     }

      

     Person(String name,intage,String address){

         this(name,age);

         this.address = address;

         System.out.println("三个参数的构造函数");

     }

      

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

建立如下java工程

Person.java

class Person {

     String name;

     intage;

     String address;

      

     Person(){

         System.out.println("无参数的构造函数");

     }

 

     Person(String name,intage){

         this();

         this.name = name;

         this.age = age;

         System.out.println("两个参数的构造函数");

     }

      

     Person(String name,intage,String address){

         this(name,age);

         this.address = address;

         System.out.println("三个参数的构造函数");

     }

      

     void talk(String name){

         System.out.println("my name is "+this.name);

     }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person p1 = new Person("zhangsan",20,"beijing");

    }

}

运行结果

无参数的构造函数

两个参数的构造函数

三个参数的构造函数

17_static关键字的作用

主要内容:

  1. 静态成员变量的语法特点
  2. 静态函数的语法特点
  3. 静态代码块的语法特点

1.静态成员变量的语法特点

可以使用类名来调用(也可以用对象来调用),比如

Person.java

class Person {

     staticinti;

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person.i = 10;

    }

}

 

普通的成员变量

Person p1 = new Person();

p1.i = 10;

Person p2 = new Person();

p2.i = 20;

修改p1.i的值不影响p2.i的值

静态的成员变量

Person p1 = new Person();

Person p2 = new Person();

Person.i = 10;

P1p2使用同一个成员变量,也就是说所有的对象使用的成员变量的值都是同一份

Person.java

class Person {

     staticinti;

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person p1 = new Person();

        Person p2 = new Person();

        Person.i = 1;//此处改为p1.i=1;是一样的效果

        System.out.println("p1.i的值为"+p1.i);

        System.out.println("p2.i的值为"+p2.i);

    }

}

运行结果

p1.i的值为1

p2.i的值为1

 

2.静态函数的语法特点

可以使用类名来调用,比如

Person.java

class Person {

     staticvoid fun(){

         System.out.println("我是静态函数");

     }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person.fun();

    }

}

运行结果

我是静态函数

 

下边的用法是正确的

Person.java

class Person {

     String name;

     void talk(){

         System.out.println("my name is"+this.name);

     }

}

在静态函数中不能直接引用非静态的成员变量,下边的用法是错误的

class Person {

     String name;

     staticvoid talk(){

         System.out.println("my name is"+name);

     }

}

注意:此处不能用this.name因为静态函数调用直接用"类名.函数"如Person.fun(); 这样就不存在调用函数的那个对象的问题,所以不能用this,而直接加name又解释不通,所以不能这样用。

但是如果name这个变量是静态的,如下写法就可以了

Person.java

class Person {

     static String name;

     staticvoid talk(){

         System.out.println("my name is "+name);

     }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person.name = "zhangsan";

        Person.talk();

    }

}

运行结果

my name is zhangsan

 

3.静态代码块的语法特点

静态代码块无需调用,只要类中含有静态代码块,装载类的时候就会调用静态代码块。静态代码块的主要作用就是为静态变量赋值

Person.java

class Person {

 

     static{

         System.out.println("静态代码块");

     }

      

     static String name;

     staticvoid talk(){

         System.out.println("my name is "+name);

     }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person.name = "zhangsan";

        Person.talk();

 

    }

}

运行结果

静态代码块

my name is zhangsan

 

总结:

  1. 静态成员变量只有一份;
  2. 在静态函数当中不能使用this;
  3. 静态代码块的主要作用是为静态成员变量赋值。

 

18_继承初步

主要内容:

  1. 什么是继承?
  2. 为什么要使用继承?
  3. 继承的基本语法特点

1.什么是继承?

在现实世界中,继承就是儿子得到了老子的东西;在面向对象的世界中,继承就是一个类得到了另外一个类当中的成员变量和成员方法。

Java中只支持单继承,不允许多继承。一个子类只允许继承一个父类,一个父类可以拥有多个子类。

Person.java

class Person {

     String name;

     intage;

     void eat(){

         System.out.println("吃饭");

     }

     void introduce(){

         System.out.println("我的名字是"+name+",我的年龄是"+age);

     }

}

Student.java

class Student extends Person{

 

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student student = new Student();

        student.name = "张三";

        student.age = 16;

        

        student.eat();

        student.introduce();

    }

}

吃饭

我的名字是张三,我的年龄是16
Student继承了Person的成员变量和成员函数,还可以拥有自己的成员变量和成员函数

class Student extends Person{

    intgrade;

    

    void study(){

        System.out.println("学习");

    }

}

eg:

Person.java

class Person {

      

     String name;

     intage;

      

     void eat(){

         System.out.println("吃饭");

     }

      

     void introduce(){

         System.out.println("我的名字是"+name+",我的年龄是"+age);

     }

 

}

Student.java

class Student extends Person{

    intgrade;

    

    void study(){

        System.out.println("学习");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student student = new Student();

        student.name = "张三";

        student.age = 16;

        student.grade = 3;

        student.eat();

        student.introduce();

        student.study();

    }

}

运行结果

吃饭

我的名字是张三,我的年龄是16

学习

2.为什么要使用继承?

如果两个类或更多的类拥有共同的成员变量和成员函数,就可以把这些成员变量和成员函数放到父类里边去,也就是重复的代码都放到父类去,然后这子类去继承这个父类。今天这些共同的代码需要修改时,只需要在父类中进行修改即可。

使用继承是为了减少重复代码,另外子类还可以在继承父类的基础上进行扩展

子类可以继承父类的成员变量和成员函数,但是不能继承父类的构造函数

19_子类实例化过程

主要内容:

  1. 生成子类的过程
  2. 使用super调用父类构造函数的方法

1.生成子类的过程

Person.java

class Person {

      

     String name;

     intage;

      

     Person(){

         System.out.println("Person的无参数构造函数");

     }

      

     Person(String name,intage){

         this.name = name;

         this.age = age;

         System.out.println("Person的有参数的构造函数");

     }

      

     void eat(){

         System.out.println("吃饭");

     }

    

}

Student.java

class Student extends Person{

    int grade;

//在子类的构造函数中,必须调用父类的构造函数

    Student(){

        System.out.println("Student的无参数构造函数");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student student = new Student();

 

    }

}

运行结果

Person的无参数构造函数

Student的无参数构造函数

2.使用super调用父类构造函数的用法

在子类的构造函数中,必须调用父类的构造函数,无明确调用父类构造函数时,编译器会自动加一行Super();用于调用父类中无参数的构造函数,如下

class Student extends Person{

    int grade;

    Student(){

        Super();

        System.out.println("Student的无参数构造函数");

    }

}

Student从父类中继承了两个成员变量,自身有一个成员变量,要为三个成员变量赋值如果写成如下的构造函数的话,会显得跟父类中的构造函数重复

Student.java

class Student extends Person{

    intgrade;

    Student(){

        System.out.println("Student的无参数构造函数");

    }

    

    Student(String name,intage,intgrade){

        this.name = name;

        this.age = age;

        this.grade = grade;

    }

}

为了避免重复,可以使用supper调用父类中的构造函数,具体调用父类中的哪个构造函数由super后边的参数来决定,完整程序如下

Person.java

class Person {

      

     String name;

     intage;

      

     Person(){

         System.out.println("Person的无参数构造函数");

     }

      

     Person(String name,intage){

         this.name = name;

         this.age = age;

         System.out.println("Person的有参数的构造函数");

     }

      

     void eat(){

         System.out.println("吃饭");

     }

    

}

 

Student.java

class Student extends Person{

    

    intgrade;

    Student(){

        System.out.println("Student的无参数构造函数");

    }

    

    Student(String name,intage,intgrade){

        super(name,age);//一定要是这个函数的第一条语句,跟this一个道理

        this.grade = grade;

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student student = new Student("zhangsan",18,3);

        System.out.println(student.name);

        System.out.println(student.age);

        System.out.println(student.grade);

    }

}

运行结果

Person的有参数的构造函数

zhangsan

18

3

20_函数的复写

主要内容:

  1. 函数的复写(override
  2. 使用super调用父类的成员函数

1.函数的复写

(override)也成覆盖或重写:①在具有父子关系的两个类当中;②父类和子类各有一个函数,这两个函数的定义(返回值类型、函数名和参数列表)完全相同。

下边的例子,标黄的部分构成了函数的复写

Person.java

class Person {

      

     String name;

     intage;

      

     void introduce(){

         System.out.println("我的姓名是"+ name+"我的年龄是"+age);

     }

    

}

Student.java

class Student extends Person{

    String address;

    

    void introduce(){

        System.out.println("我的性命是"+name+"我的年龄是"+age);

        System.out.println("我的家在"+address);

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student s= new Student();

        s.name = "张三";

        s.age = 20;

        s.address = "北京";

        s.introduce();

 

    }

}

运行结果

我的性命是张三我的年龄是20

我的家在北京

2.使用super调用父类的成员函数(方法)

在函数的复写例子中两个函数存在重复,这就可以采用super调用父类的成员函数

Student.java做如下改动

class Student extends Person{

    String address;

    

    void introduce(){

        super.introduce();

        System.out.println("我的家在"+address);

    }

}

运行结果是一样的,这里super.introduce();可以不写在introduce()的第一行

可以如下写

    void introduce(){

        System.out.println("我的家在"+address);

super.introduce();

    }

21_对象的转型(很重要)

主要内容:

  1. 对象的向上转型
  2. 对象的向下转型

1.对象的向上转型

向上转型-------将子类的对象赋值给父类的引用,现实生活中比如笔记本电脑属于电脑,茶杯属于杯子。比如下边的例子:Student是Person的子类,把一个Student类型的对象s赋值给一个Person类型的引用p

下边的例子编译会出错

Person.java

class Person {

      

     String name;

     intage;

      

     void introduce(){

         System.out.println("我的姓名是"+ name+"我的年龄是"+age);

     }

    

}

Student.java

class Student extends Person{

    String address;

    void study(){

        System.out.println("我正在学习");

    }

    void introduce(){

        super.introduce();

        System.out.println("我的家在"+address);

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Student s = new Student();

        Person p = s;

        

        p.name = "张三";

        p.age = 20;

        p.address = "北京"

 

    }

}

p.address = "北京";这样用是错误的,一个引用能够调用哪些成员(变量和函数),取决于这个引用的类型

将Test.java改为如下

class Test {

    publicstaticvoid main(String args []){

        Student s = new Student();

        Person p = s;

        //Person p = new Student(); //这样写与上边两行一个效果

        p.name = "张三";

        p.age = 20;

        //p.address = "北京"

        p.introduce();

    }

}

运行结果为

我的姓名是张三我的年龄是20

我的家在null

从运行结果看p.introduce();这里p调用的是子类的introduce一个引用调用的是哪一个方法取决于这个引用所指向的对象

2.对象的向下转型

向下转型--------将父类的对象赋值给子类的引用

 

向下成功的前提是先把一个对象向上转型,然后再把对象向下转型转回来,如下

Test.java

class Test {

    publicstaticvoid main(String args []){

        //正确的向下转型

        Person p = new Student();

        Student s = (Student)p;

        

        //错误的向下转型

        //Person p = new Person();

        //Student s = (Student)p;

    }    

}

22_面向对象应用(一)

 

Printer.java

class Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(String s){

        System.out.println("print-->"+s);

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Printer printer = new Printer();

        printer.open();

        printer.print("abc");

        printer.close();

    }

}

运行结果:

Open

print-->abc

close

需求:控制两台打印机,但两台打印机不是一个牌子,一个HP,一个Canon,佳能打印机有个特殊的地方,关机前会清洗一下喷头

HPPrinter.java

class HPPrinter {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(String s){

        System.out.println("print-->"+s);

    }

}

CanonPrinter.java

class CanonPrinter {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        this.clean();

        System.out.println("close");

    }

    

    void print(String s){

        System.out.println("print-->"+s);

    }

    

    void clean(){

        System.out.println("clean");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        intflag = 1;

        

        if(flag==0){

            HPPrinter hpPrinter = new HPPrinter();

            hpPrinter.open();

            hpPrinter.print("abc");

            hpPrinter.close();

        }

        elseif(flag==1){

            CanonPrinter cannonPrinter = new CanonPrinter();

            cannonPrinter.open();

            cannonPrinter.print("abc");

            cannonPrinter.close();

            

        }

        

    }

}

运行结果:

Open

print-->abc

clean

close

 

HPPrinter.java与CanonPrinter.java存在重复代码,不仅如此,比如现在用户在open

打印机前需要验证用户身份,HPPrinter.java与CanonPrinter.java里的open()函数都需要修改。

修改思路:新建一个父类Printer,HPPrinter和CanonPrinter都继承这个父类

Printer.java

class Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(String s){

        System.out.println("print-->"+s);

    }

}

HPPrinter.java

class HPPrinter extends Printer{

 

}

CanonPrinter.java

class CanonPrinter extends Printer{

    

    void close(){

        this.clean();

        super.close();

    }

    

    void clean(){

        System.out.println("clean");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        intflag = 1;

        

        if(flag==0){

            HPPrinter hpPrinter = new HPPrinter();

            hpPrinter.open();

            hpPrinter.print("abc");

            hpPrinter.close();

        }

        elseif(flag==1){

            CanonPrinter cannonPrinter = new CanonPrinter();

            cannonPrinter.open();

            cannonPrinter.print("abc");

            cannonPrinter.close();

            

        }

 

        

    }

}

运行结果

Open

print-->abc

clean

close

这时就比较简单了,修改代码的代价就小了,因为我们把重复代码集中到父类中去了,新建一个打印机的类去继承Printer就行

23_抽象类和抽象函数

主要内容:

  1. 抽象函数的语法特征
  2. 抽象类的语法特征
  3. 抽象类的作用

 

什么是抽象函数

    只有函数的定义,没有函数体的函数被称为抽象函数:

            abstractvoid fun();

 

什么是抽象类

使用abstract定义的类被称之为抽象类:

  1. 抽象类不能够生成对象;
  2. 如果一个类当中包含有抽象函数,那么这个类必须被声明为抽象类;
  3. 如果一个类当中没有抽象函数,那么这个类也可以被定义为抽象类。

 

Person.java

abstractclass Person {

      

     String name;

     intage;

      

     void introduce(){

         System.out.println("我的姓名是"+ name+",我的年龄是"+age);

     }

     

     abstractvoid eat();

}

抽象类不能生成对象,但是其子类可以生成对象。抽象类是天生当爹的(天生用来当父类的

如果子类写成Chinese.java

class Chinese extends Person{

 

}

这样编译是过不了的,因为Chinese从Person中继承了抽象函数,如果一个类当中含有抽象函数,这个类必须为抽象类。所以应该写成

Chinese.java

abstractclass Chinese extends Person{

}

除了这种解决方法外,还可以复写(overwrite

Chinese.java

class Chinese extends Person{

    void eat(){

        System.out.println("用筷子吃饭");

    }

}

这时Chinese里就没有抽象函数了,因为我们复写了eat()函数,给函数加了函数体。

Person.java

abstractclass Person {

      

     String name;

     intage;

      

     voidintroduce(){

         System.out.println("我的姓名是"+ name+",我的年龄是"+age);

     }

     

     abstractvoid eat();

}

Chinese.java

class Chinese extends Person{

    void eat(){

        System.out.println("用筷子吃饭");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person p = new Chinese();//向上转型

        p.eat();

 

    }    

}

运行结果

用筷子吃饭

Person.java

abstractclass Person {

     Person(){

         System.out.println("Person的构造函数");

     }

     String name;

     intage;

      

     void introduce(){

         System.out.println("我的姓名是"+ name+",我的年龄是"+age);

     }

     

     abstractvoid eat();

}

Chinese.java

class Chinese extends Person{

    Chinese(){

        System.out.println("Chinese的构造函数");

    }

    void eat(){

        System.out.println("用筷子吃饭");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Person p = new Chinese();

        p.eat();

 

    }    

}

运行结果

Person的构造函数

Chinese的构造函数

用筷子吃饭

结论:抽象类可以有构造函数,该构造函数是为子类调用时准备的

总结:

  1. 抽象函数就是没有函数体的函数;
  2. 抽象类使用abstract来定义;
  3. 抽象类不能生成对象,但是却可以拥有构造函数。

24_为什么用抽象类

抽象类表达的是一种概念。比如打印机就是一个概念,分为针式打印机和喷墨式打印机,不同的打印机有不同的打印方法。汽车是一个概念,手动挡跟自动挡是不同的驾驶方法,所以对于汽车开的方法没办法写一个具体的drive()函数。

Printer.java

class Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(){

 

    }

}

HPPrinter.java

//该打印机为喷墨打印机

class HPPrinter extends Printer{

    void print(){

        System.out.println("使用喷墨打印机进行打印");

    }

}

CanonPrinter.java

//该打印机为针式打印机

class CanonPrinter extends Printer{

    void print(){

        System.out.println("使用针式打印机进行打印");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Printer p1 = new HPPrinter();

        p1.open();

        p1.print();

        p1.close();

        

        Printer p2 = new CanonPrinter();

        p2.open();

        p2.print();

        p2.close();

    }

}

运行结果

Open

使用喷墨打印机进行打印

close

Open

使用针式打印机进行打印

Close

 

现在假设Printer.java是张三写的,HPPrinter.java是李四写的,如果HPPrinter.java忘了复写print()函数,编译没错但是运行会出现问题(因为Printer.javaprint函数是空的)。为了避免这个问题可以使用抽象类,这样HPPrinter.java忘了复写print()函数编译会出错,这样就会提醒李四复写print()函数

Printer.java

abstractclass Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    abstractvoid print();

}

 

父类定义为抽象类,函数无法具体写出只能由子类自己去实现,这个函数可以定义为抽象函数。这样子类就不会忘记复写父类中这个抽象函数,忘写了编译会出错

 

如果一段代码在语意上是有错误的,那么在语法上也应该是有错误的。比如

Printer.java

abstract class Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(){

    }

}

标注的这个函数体为空,在语意上是错误的。如果改成abstractvoid print();就统一了,这样子类不复写在语法上就会出错。

总结:如果一个类的某一个函数我们无法具体给出,或者说这个函数必须由其子类来实现,最好的方法就是把这个函数定义为抽象函数,并且把这个类定义为抽象类。这样强烈要求子类在继承父类时对这个函数进行复写。

25_包和访问权限(一)

主要内容:

  1. 什么是Java当中的软件包?
  2. 为什么要使用软件包?
  3. 如何给一个类打包?

为什么要使用软件包

一个团队开发学校管理系统,A组开发大学里人员模型(User父类,Student和Teacher子类),B组开发用户管理系统(User父类,RegUser和UnRegUser子类)。两个User类名字一样,但是代码可能不同,如果把两组代码合并就会出问题,因为同组文件夹下不会出现两个文件同名。这时就会用到软件包,所谓软件包就是把类放到不同的文件夹下

如何给一个类打包

如在E:\java4android新建一个Test.java

package mars;

//将类放置到一个包当中,需要使用 package "包名"

//编译时需要使用-d参数,该参数的作用是依照包名生成相应的文件夹

//一个类的全名应该是"包名"+"."+"类名"

class Test {

    publicstaticvoid main(String args []){

        System.out.println("Hello package");

    }

}

编译方法

Javac –d . Test.java

-d意思是根据包名生成文件夹

. 的意思是在当前目录

编译前

编译后

注意:一个类一旦打了包,这个类的名字就会发生变化。名字变为 包名.类名

上述例子打完包,类名变为 mars.Test

在E:\java4android目录下运行

 

包名的命名规范(不是硬性规定):

  1. 要求包名所有的子母都要小写;
  2. 包名一般情况下,是你的域名倒过来写,比如域名为marsdroid.org,包名为org.marsdroid

    如果包名为org.marsdroid编译后先生成一个org文件夹,然后在org文件夹下生成一个marsdroid文件夹。包名多一个".",生成的文件夹就多一级目录

Test.java

package org.marsdroid;

 

class Test {

    publicstaticvoid main(String args []){

        System.out.println("Hello package");

    }

}

编译

运行

总结:

  1. 软件包为Java类提供了命名空间;
  2. 打包需要使用package指令;
  3. 一个类的全名应该是"包名"+"."+"类名"。

 

 

26_包和访问权限(二)

主要内容:

  1. Java当中的访问权限
  2. 软件包的导入

1.Java当中的访问权限

(1)public 公共权限

一个类名如果定义为public,那么这个类名与文件名必须一致。如

Person.java

package org.marsdroid

 

publicclassPerson{

    public String name;

    publicintage;

    

    publicvoid introduce(){

        System.out.println(name);

    }

}

Test.java

package com.marsdroid;

 

class Test {

    publicstaticvoid main(String args []){

        org.marsdroid.Person p = null;

        System.out.println("Hello package");

    }

}

PersonTest不在同一个包中,如果Person不是public,在Test中就无法使用Person

 

Person.java

package org.marsdroid;

 

publicclass Person {

    public String name;

    publicintage;

    

    publicvoid introduce(){

        System.out.println(name);

    }

}

Test.java

package com.marsdroid;

 

class Test {

    publicstaticvoid main(String args []){

        org.marsdroid.Person p = new org.marsdroid.Person();

        p.name = "zhangsan";

        System.out.println(p.name);

    }

}

如果要在一个包的外部调用一个对象的一个成员变量或成员函数的话,这个变量或函数必须是public权限

 

(2)private 私有权限

Person.java

package org.marsdroid;

 

class Person {

    private String name;

    privateintage;

    

    privatevoid introduce(){

        System.out.println(name);

    }

}

Test.java

package org.marsdroid;

 

class Test {

    publicstaticvoid main(String args []){

        Person p = new Person();//因为跟Person在同一个包里,可以直接用

        p.name = "zhangsan";

    }

}

name只能在Person类中使用,在类的外部无法使用,因为name被定义为private

(3)default 包级别访问权限

如果两个类在同一个包中,default权限是不受限制的

Person.java

package org.marsdroid;

class Person {

    String name;

    intage;

    

    void introduce(){

        System.out.println(name);

    }

}

Test.java

package org.marsdroid;

class Test {

    publicstaticvoid main(String args []){

        Person p = new Person();

        p.name = "zhangsan";

        p.introduce();

    }

}

如果两个类不在同一个包中,default权限是受限制的

Person.java

package org.marsdroid;

 

class Person {

    String name;

    intage;

    

    void introduce(){

        System.out.println(name);

    }

}

 

Test.java

package com.marsdroid;

 

class Test {

    publicstaticvoid main(String args []){

        org.marsdroid.Person p = new org.marsdroid.Person();

        p.name = "zhangsan";

        p.introduce();

    }

}

也就是说:如果一个类不是public在包的外部是无法访问的

总结:public可以修饰类、成员变量和成员函数,没有任何限制,同一个包当中,或者不同包当中的类都可以自由访问;private可以修饰成员变量和成员函数,只能在本类当中使用;default(不写权限修饰符就是default权限)可以修饰类、成员变量和成员函数,在同一个包中可以自由访问。

2.包的导入问题

Person.java

package org.marsdroid;

 

publicclass Person {

    public String name;

    publicintage;

    

    publicvoid introduce(){

        System.out.println(name);

    }

}

Test.java package com.marsdroid;

 

import org.marsdroid.Person;

class Test {

    publicstaticvoid main(String args []){

        Person p = new Person();//导入包再访问就不用那么麻烦了

        p.name = "zhangsan";

        p.introduce();

    }

}

如果包org.marsdroid下有很多类Test都用了,导入包可以写为import org.marsdroid.*;

27_包和访问权限(三)

主要内容:

  1. 访问权限与继承
  2. protected权限

1.访问权限与继承

Person.java

package com.marsdroid;

public class Person {

    String name;

    intage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Student.java

package org.marsdroid;

 

import com.marsdroid.Person;

class Student extends Person{

    void introduce(){

        System.out.println("我的名字是"+name+",我的年龄是"+age);

    }    

 

}

如果子类和父类不在同一个包中,则子类可以继承到父类当中的default权限的成员变量和成员函数,但是由于权限不够,无法使用

解决办法:name和age定义为public

Person.java

package com.marsdroid;

publicclass Person {

    public String name;

    publicintage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Student.java

package org.marsdroid;

 

import com.marsdroid.Person;

class Student extends Person{

    void introduce(){

        System.out.println("我的名字是"+name+",我的年龄是"+age);

    }    

 

}

这个时候编译没有任何问题

如果Person和Student在同一个包中

Person.java

package org.marsdroid;

public class Person {

    String name;

    intage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Student.java

package org.marsdroid;

 

class Student extends Person{

    void introduce(){

        System.out.println("我的名字是"+name+",我的年龄是"+age);

    }    

 

}

编译没有任何问题

如果Person中name和age定义为private,那么name和age只能在Person的内部使用,Student中无法使用。

Person.java

package com.marsdroid;

public class Person {

    private String name;

    private intage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Student.java

package org.marsdroid;

 

import com.marsdroid.Person;

class Student extends Person{

    void introduce(){

        System.out.println("我的名字是"+name+",我的年龄是"+age);

    }    

 

}

2.protected权限

protected权限拥有和default一样的功能,但是该权限只能修饰成员变量和成员函数

Person和Student不在一个包中,如果Person中name和age定义为protected,那么子类可以继承使用

Person.java

package com.marsdroid;

publicclass Person {

    protected String name;

    protectedintage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Student.java

package org.marsdroid;

 

import com.marsdroid.Person;

class Student extends Person{

    void introduce(){

        System.out.println("我的名字是"+name+",我的年龄是"+age);

    }    

 

}

 

public和protected的区别

Person.java

package com.marsdroid;

publicclass Person {

    public String name;

    protectedintage;

    

    void eat(){

        System.out.println("eat");

    }

    

    void sleep(){

        System.out.println("sleep");

    }

}

Test.java

package org.marsdroid;

 

import com.marsdroid.Person;

class Test {

    publicstaticvoid main(String args []){

        Person p = new Person();

        p.name = "zhangsan";

        p.age = 10;

    }

}

子类跟父类在不同包中,子类可以访问父类中protected权限的成员变量和成员函数,如果两个类不是父子关系,那么不能访问protected权限的成员变量和成员函数;public权限,即使两个类分别在两个包中,没有父子关系也可以使用

权限

public > protected > default > private

面向对象的封装性原则:一个类和一个成员变量或者成员函数的权限应该尽可能的小。

28_接口的基本语法(最重要)

主要内容:

  1. 什么是接口?
  2. 接口的基本语法

 

1.什么是接口?

USB接口可以接MP3、手机、电扇、冰箱

定义了接口就是定义了调用对象的标准

2.接口的基本语法

(1)接口的基本语法(一)

  1. 使用interface定义;
  2. 接口当中的方法都是抽象方法(省略abstract关键字);
  3. 接口当中的方法都是public权限;

     

Implements(实现)是特殊的继承

实现接口使用implements关键字

USB.java

interface USB {

    publicvoid read();

    

    publicvoid write();

}

Phone.java

class Phone implements USB{

    publicvoid read(){

        System.out.println("Phone read");

    }

    

    publicvoid write(){

        System.out.println("Phone write");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Phone phone = new Phone();

        USB usb = phone;//向上转型

        usb.read();

        usb.write();

    }

}

编译运行

Phone read

Phone write

(2)接口的基本语法(二)

  1. 实现接口使用implements关键字;
  2. 一个类可以实现多个接口;
  3. 一个接口可以继承多个接口(区别于继承:一个子类只允许继承一个父类);

b.一个类可以实现多个接口

现在编写Phone既支持USB接口又支持WiFi接口

USB.java

interface USB {

    publicvoid read();

    

    publicvoid write();

}

WiFi.java

interface WiFi {

    publicvoid open();

    publicvoid close();

}

Phone.java

class Phone implements USB,WiFi{

    publicvoid read(){

        System.out.println("Phone read");

    }

    

    publicvoid write(){

        System.out.println("Phone write");

    }

    

    publicvoid open(){

        System.out.println("WiFi open");

    }

    

    publicvoid close(){

        System.out.println("WiFi close");

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Phone phone = new Phone();

        USB usb = phone;

        usb.read();

        usb.write();

        

        WiFi wifi = phone;

        wifi.open();

        wifi.close();

    }

}

编译运行

Phone read

Phone write

WiFi open

WiFi close

c.一个接口可以继承多个接口

A.java

interface A {

    publicvoid funA();

}

B.java

interface B {

    publicvoid funB();

}

C.java

interface C extends A,B {

    publicvoid funC();

}

C接口继承了A跟B接口

 

29_接口的应用

主要内容:

  1. 为什么要使用接口?
  2. 工厂方法模式

1.为什么要使用接口?

回看22_面向对象应用(一)里的打印机程序

Printer.java

class Printer {

    void open(){

        System.out.println("Open");

    }

    

    void close(){

        System.out.println("close");

    }

    

    void print(String s){

        System.out.println("print-->"+s);

    }

}

HPPrinter.java

class HPPrinter extends Printer{

 

}

CanonPrinter.java

class CanonPrinter extends Printer{

    

    void close(){

        this.clean();

//super调用父类成员函数可以不写在第一行,调用父类构造函数必须写在第一行

        super.close();

    }

    

    void clean(){

        System.out.println("clean");

    }

}

会发现,这里的程序不太合理,因为不可能打印机的开机、关机、打印方法都一样,直接继承就行。不同的打印机有不同的开机、关机、打印方法,但是不论什么打印机都应该有开机、关机、打印这三个行为,具体这三个行为该怎么执行的,那是每一个打印机自己要完成的工作。所以把打印机这个类换成接口,会更合理一些。

Printer.java

interface Printer {

    publicvoid open();

 

    publicvoid close();

    

    publicvoid print(String s);

}

HPPrinter.java

class HPPrinter implements Printer{

    publicvoid open(){

        System.out.println("HP open");

    };

 

    publicvoid close(){

        System.out.println("HP close");

    };

    

    publicvoid print(String s){

        System.out.println("HP print-->"+s);

    };

}

CanonPrinter.java

class CanonPrinter implements Printer{

    privatevoid clean(){

        System.out.println("clean");

    }

    publicvoid close(){

        this.clean();

        System.out.println("Canon close");

    }

    publicvoid open(){

        System.out.println("Canon open");

    }

    publicvoid print(String s){

        System.out.println("Canon print-->"+s);

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

//根据用户选择生成相应的打印机对象,并且向上转型为Printer类型

        Printer printer = null;

        intflag = 0;

        if(flag==0){

            printer = new HPPrinter();

        }

        elseif(flag==1){

            printer = new CanonPrinter();

        }

        printer.open();

        printer.print("Test");

        printer.close();

    }

}

编译运行

HP open

HP print-->Test

HP close

程序还是不完善,因为Test.java中标注的部分程序,如果有100个地方需要用到打印机,就需要出现100次标注的程序。或者说如果再添加一台XXX打印机,这些用到打印机的地儿都需要修改。可以定义一个类,类中定义一个函数,提供打印功能

Printer.javaHPPrinter.javaCanonPrinter.java程序不变

PrinterFactory.java

class PrinterFactory {

    publicstatic Printer getPrinter(intflag){

        Printer printer = null;

        if(flag==0){

            printer = new HPPrinter();

        }

        elseif(flag==1){

            printer = new CanonPrinter();

        }        

        returnprinter;

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Printer printer = PrinterFactory.getPrinter(0);

        printer.open();

        printer.print("Test");

        printer.close();

    }

}

编译运行

HP open

HP print-->Test

HP close

如果再添加一台XXX打印机,只需添加一个XXXPrinter.java,修改PrinterFactory.java

XXXPrinter.java

class XXXPrinter implements Printer{

    publicvoid open(){

        System.out.println("XXX open");

    };

 

    publicvoid close(){

        System.out.println("XXX close");

    };

    

    publicvoid print(String s){

        System.out.println("XXX print-->"+s);

    };

}

PrinterFactory.java

class PrinterFactory {

    publicstatic Printer getPrinter(intflag){

        Printer printer = null;

        if(flag==0){

            printer = new HPPrinter();

        }

        elseif(flag==1){

            printer = new CanonPrinter();

        }

        elseif(flag==2){

            printer = new XXXPrinter();

        }

        returnprinter;

    }

}

换打印机时只需要修改Test.java中的Printer printer = PrinterFactory.getPrinter(0);参数即可

2.工厂方法模式

上述例子就是工厂方法模式

对于使用打印机的人来说并不知道打印机有哪些子类,用时只调用PrinterFactory里的函数,假设HPPrinter坏了,只需去掉HPPrinter类,并在PrinterFactory里修改就行,而这些用户不需要知道

30_Java当中的异常(一)

主要内容:

  1. 什么是异常
  2. 异常的分类
  3. try…catch…finally结构的使用方法

1.什么是异常

 

异常在程序运行时才会出现,跟程序编译没啥关系

Test.java

class Test{

    publicstaticvoid main(String args[]){

        //uncheck exception

        inti=1/0;

    }

}

编译时没问题,运行时出现算术异常

2.异常的分类

图中的类都是用来创建异常的对象的,都是jdk所提供的类。Throwable是父类,有两个子类。Error是错误,是虚拟机运行时所产生的错误。一旦产生错误,虚拟机直接就会关闭。我们能做就是尽可能的减少error的产生。Exception是异常,RuntimeException(也称运行时异常)是其子类,是运行时异常。如果代码爆出来的异常是RuntimeException及RuntimeException的子类都属于uncheck Exception(需要try…catch进行处理,否则代码无法编译),如果程序暴出来异常是Exception除了RuntimeException之外的直接子类就属于check exception(也称编译时异常),编译器会强制你去处理这样的exception

来看个CheckException的例子

CheckException.java

class TestCheck {

    publicstaticvoid main(String args []){

        //check exception

        Thread.sleep(1000);

    }

}

3. try…catch… finally结构的使用方法

Test.java

class Test{

    publicstaticvoid main(String args[]){

        System.out.println(1);

        inti=1/0;

        System.out.println(2);

    }

}

Test.java

class Test{

    publicstaticvoid main(String args[]){

        System.out.println(1);

        try{

            System.out.println(2);

            inti = 1/0;//此行出现异常,下边的程序不再运行直接跳到catch

            System.out.println(3);

        }

        catch(Exception e){

            e.printStackTrace();

            System.out.println(4);

        }

        System.out.println(5);

    }

}

把有可能出现异常的代码放进try里,catch用于捕捉异常,出现异常后try里边出现异常的代码后边的代码就不再运行了,跳到catch里。如果程序没有异常catch里的代码不运行。比如

Test.java

class Test{

    publicstaticvoid main(String args[]){

        System.out.println(1);

        try{

            System.out.println(2);

            inti = 1/1;

            System.out.println(3);

        }

        catch(Exception e){

            e.printStackTrace();

            System.out.println(4);

        }

        System.out.println(5);

    }

}

下边的例子必须进行try… catch处理,否则编译不过

CheckException.java

class TestCheck {

    publicstaticvoid main(String args []){

        //check exception

        Thread.sleep(1000);

    }

}

加上try …catch

CheckException.java

class TestCheck {

    publicstaticvoid main(String args []){

        //check exception

        try{

            Thread.sleep(1000);

        }

        catch(Exception e){

            e.printStackTrace();

        }

    }

}

 

try…catch…finally结构,try里边的代码出异常执行catch,不出异常不执行catch,而不论出不出异常都会执行finally

Test.java

class Test{

    publicstaticvoid main(String args[]){

        System.out.println(1);

        try{

            System.out.println(2);

            inti = 1/1;

            System.out.println(3);

        }

        catch(Exception e){

            e.printStackTrace();

            System.out.println(4);

        }

        finally{

            System.out.println("finally");

        }

        System.out.println(5);

    }

}

 

总结:

  1. 程序员对Error无能为力,只能处理Exception
  2. 对异常的处理关系到系统的健壮性
  3. 使用try…catch…finally来处理可能出现异常的代码。

31_Java当中的异常(二)

主要内容:

  1. throw的作用
  2. throws的作用

1.throw的作用

throw抛出方法体内的一个异常,抛出之后如果不用try…catch处理就中止指令。

假设代码如下

User.java

class User{

    privateintage;

    publicvoid setAge(intage){

        this.age = age;

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User user = new User();

        user.setAge(-20);

    }

}

程序是有问题的,因为年龄不可能为负。有问题怎么办呢?应该产生一个RuntimeException异常

User.java

class User{

    privateintage;

    publicvoid setAge(intage){

        if(age<0){

            RuntimeException e = new RuntimeException("年龄不能为负数");

            throw e;//抛出异常,终止程序运行

        }

        

        this.age = age;

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User user = new User();

        user.setAge(-20);

    }

}

RuntimeException e = new RuntimeException("年龄不能为负数");uncheck exception如果改为check exception

User.java

class User{

    privateintage;

    publicvoid setAge(intage){

        if(age<0){

            Exception e = new Exception("年龄不能为负数");

            throwe;

        }

        

        this.age = age;

    }

}

从编译结果看check exception必须对其进行捕获(try…catch)或声明

2.throws的作用

    throws是在定义方法时候声明一个异常,原方法(函数)将不负责处理这个异常,而是谁调用这个方法,谁就处理这个异常

User.java

class User{

    privateintage;

    publicvoid setAge(intage) throws Exception{

        if(age<0){

            Exception e = new Exception("年龄不能为负数");

            throwe;

        }

        

        this.age = age;

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User user = new User();

        user.setAge(-20);

    }

}

throws作用是程序中可能产生check exception的时候,把可能产生异常的代码处理一下,采用throws进行声明,一旦声明了,声明部分的程序就没有责任来处理异常,而是由调用这个函数的地方来处理异常

所以Test.java应来处理异常,应改为

class Test {

    publicstaticvoid main(String args []){

        User user = new User();

        try{

            user.setAge(-20);

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

32_Java当中的IO(一)

主要内容:

  1. I/O操作的目标
  2. IO的分类方法
  3. 读取文件和写入文件的方法

1.I/O操作的目标

从数据源当中读取数据,以及将数据写入到数据目的地当中;

2.IO的分类(了解一下即可)

第一种分法:

  1. 输入流;
  2. 输出流;

第二种分法:

  1. 字节流;
  2. 字符流;

第三种分法:

  1. 节点流;
  2. 处理流

 

InputStream和OutputStream是所有字节流的父类,都是抽象类,或者说所有的字节流都是其子类。InputStream最常用的子类是FileInputStream,用于从硬盘的文件当中读取数据,OutputStream最常用的子类是FileOutputStream,用于把数据写入到硬盘的文件当中。

3.读取文件和写入文件的方法

核心类的核心方法:

    InputStream:

    int read(byte [] b,int off,int len)

    OutputStream:

    void write(byte [] b,int off,int len)

 

int read(byte[] b,int off,int len) byte[] b为byte类型的数组,off为偏移量,也就是读进来的数据从数组的第几位开始放,len为存放数据的长度。read的返回值为这一次读取数据的字节数。注意read三个参数及返回值的意义

void write(byte [] b,int off,int len) byte[] b为要往文件里写的数据,要往文件里写什么数据就先把数据变成byte类型的数组,然后再往文件里边写

e:/java4android/下新建内容为"abcd"from.txt

Test.java

//第一步:导入类

import java.io.*;

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[100];

            //调用输入流对象的read方法读取数据

            fis.read(buffer,0,buffer.length);

            for(inti=0;i<buffer.length;i++){

                System.out.println(buffer[i]);

            }

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

编译运行

97

98

99

100

0

0

……

0

 

97、98、99、100分别为a、b、c、d的ASIIC码

如果偏移量设为5,也就是fis.read(buffer,0,buffer.length);改为fis.read(buffer,5,buffer.length-5);

编译运行

0

0

0

0

0

97

98

99

100

0

0

……

0

读进来的字节怎么转换成字符呢?只需String s = new String(buffer);

Test.java

//第一步:导入类

import java.io.*;

 

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[100];

            //调用输入流对象的read方法读取数据

            fis.read(buffer,0,buffer.length);

            String s = new String(buffer);

            //调用一个String对象的trim方法,将会去除掉这个字符串的首位空格和空字符

            s.trim();

            System.out.println(s);

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

编译运行

abcd

怎么往文件里写数据呢?将from.txt读进来的数据写入到e:/java4android/to.txt 类似,定义输出流

Test.java

//第一步:导入类

import java.io.*;

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        //声明输出流引用

        FileOutputStream fos = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成代表输出流的对象

            fos = new FileOutputStream("e:/java4android/to.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[100];

            //调用输入流对象的read方法读取数据

            inttemp = fis.read(buffer,0,buffer.length);

            //String s = new String(buffer);

            //调用一个String对象的trim方法,将会去除掉这个字符串的首位空格和空字符

            //s.trim();

            //System.out.println(s);

            fos.write(buffer, 0, temp);

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

编译运行后发现e:/java4android/to.txt的内容为"abcd"

总结:

  1. I/O系统的主要目标是为了对数据进行读写操作;
  2. 数据的流向以Java程序为参照物;
  3. I/O流可以有三种分类方法;
  4. read方法和write方法。

33_Java当中的IO(二)

输入流/输出流以Java程序为参照物,流入Java程序的叫输入流,流出Java程序的叫输出流。

主要内容:

  1. 大文件的读写方法
  2. 字符流的使用方法

1.大文件的读写方法

buffer在定义时大小是固定的,但是文件的大小是不固定的。所以不可能把内容很大的文件一次性读取,应该用循环来读取。e:/java4android/from.txt大小为3698个字节

inttemp = fis.read(buffer,0,buffer.length);循环读取数据,数据读完时返回值为-1

Test.java

//第一步:导入类

import java.io.*;

 

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        //声明输出流引用

        FileOutputStream fos = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成代表输出流的对象

            fos = new FileOutputStream("e:/java4android/to.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[1024];

            while(true){

                //调用输入流对象的read方法读取数据

                inttemp = fis.read(buffer,0,buffer.length);

                if(temp == -1){

                    break;

                }

                fos.write(buffer, 0, temp);    

            }

 

            //String s = new String(buffer);

            //调用一个String对象的trim方法,将会去除掉这个字符串的首位空格和空字符

            //s.trim();

            //System.out.println(s);

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

编译运行发现e:/java4android/to.txte:/java4android/from.txt的数据完全一样

程序还不完善,因为生成了输入流跟输出流,用完时需要关上,但是关上的程序放在哪儿比较合适呢,应该放到finally,因为放到别的地儿可能会应为程序的异常执行不到。

//第一步:导入类

import java.io.*;

 

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        //声明输出流引用

        FileOutputStream fos = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成代表输出流的对象

            fos = new FileOutputStream("e:/java4android/to.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[1024];

            while(true){

                //调用输入流对象的read方法读取数据

                inttemp = fis.read(buffer,0,buffer.length);

                if(temp == -1){

                    break;

                }

                fos.write(buffer, 0, temp);    

            }

 

            //String s = new String(buffer);

            //调用一个String对象的trim方法,将会去除掉这个字符串的首位空格和空字符

            //s.trim();

            //System.out.println(s);

        }

        catch(Exception e){

            System.out.println(e);

        }

        finally{

            fis.close();

            fos.close();

        }

    }

}

finally里的close方法都会产生异常,所以finally里边还需要加try…catch.程序为

Test.java

//第一步:导入类

import java.io.*;

 

class Test {

    publicstaticvoid main(String args []){

        //声明输入流引用

        FileInputStream fis = null;

        //声明输出流引用

        FileOutputStream fos = null;

        try{

            //生成代表输入流的对象

            fis = new FileInputStream("e:/java4android/from.txt");

            //生成代表输出流的对象

            fos = new FileOutputStream("e:/java4android/to.txt");

            //生成一个字节数组

            byte[] buffer = newbyte[1024];

            while(true){

                //调用输入流对象的read方法读取数据

                inttemp = fis.read(buffer,0,buffer.length);

                if(temp == -1){

                    break;

                }

                fos.write(buffer, 0, temp);//temp=-1时就不用写了,因没读到数据    

            }

 

            //String s = new String(buffer);

            //调用一个String对象的trim方法,将会去除掉这个字符串的首位空格和空字符

            //s.trim();

            //System.out.println(s);

        }

        catch(Exception e){

            System.out.println(e);

        }

        finally{

            try{

                fis.close();

                fos.close();

            }

            catch(Exception e){

                System.out.println(e);

            }

        }

    }

}

2.字符流的使用方法

字符流:读写文件时,以字符为基础

字节输入流:Reader     其子类FileReader

方法int read(char [] c, int off,int len)

字节输出流:Writer        其子类FileWriter

方法void write(char [] c, int off,int len)

e:/java4android/to.txt 内容为"abcde"

TestChar.java

import java.io.*;

 

publicclass TestChar {

    publicstaticvoid main(String args []){

        FileReader fr = null;

        FileWriter fw = null;

        try{

            fr = new FileReader("e:/java4android/from.txt");

            fw = new FileWriter("e:/java4android/to.txt");

            char [] buffer = newchar[100];

            inttemp = fr.read(buffer, 0, buffer.length);

            for(inti=0;i<buffer.length;i++){

                System.out.println(buffer[i]);

            }

            

        }

        catch(Exception e){

            System.out.println(e);

        }

    }

}

 

编译运行

发现运行结果中有很多空字符,因为form.txt里边就abcde五个字符,而输出是100个字符,所以还有95个空字符。用inttemp = fr.read(buffer, 0, buffer.length);然后再将长度为tempd的数据写入到e:/java4android/to.txt中,注意最后需要关闭流。

TestChar.java

import java.io.*;

 

publicclass TestChar {

    publicstaticvoid main(String args []){

        FileReader fr = null;

        FileWriter fw = null;

        try{

            fr = new FileReader("e:/java4android/from.txt");

            fw = new FileWriter("e:/java4android/to.txt");

            char [] buffer = newchar[100];

            inttemp = fr.read(buffer, 0, buffer.length);

            /*

            for(int i=0;i<buffer.length;i++){

                System.out.println(buffer[i]);

            }

            */

            fw.write(buffer, 0, temp);

            

        }

        catch(Exception e){

            System.out.println(e);

        }

        finally{

            try{

                fr.close();

                fw.close();

            }

            catch(Exception e){

                System.out.println(e);

            }            

        }

    }

}

34_Java当中的IO(三)

主要内容:

  1. 处理流使用实例
  2. "装饰者(Decorator)"模式
  3. 节点流与处理流的关系

1.处理流使用实例

readLine()一次性读取一行

现有e:/java4android/users.txt内容为

张三 F 20

李四 M 21

王五 F 22

赵六 M 23

现写程序读取一行

import java.io.*;

class Test {

    publicstaticvoid main(String args []){

        FileReader fileReader = null;

        BufferedReader bufferedReader = null;

        try{

            fileReader = new FileReader("e:/java4android/users.txt");

            bufferedReader = new BufferedReader(fileReader);

            String line = bufferedReader.readLine();

            System.out.println(line);

        }

        catch(Exception e){

            System.out.println(e);

        }

        finally{

            try{

                bufferedReader.close();

                fileReader.close();

            }

            catch(Exception e){

                System.out.println(e);

            }

        }

        

    }

 

}

编译运行

张三 F 20

读取全部行

Test.java

import java.io.*;

class Test {

    publicstaticvoid main(String args []){

        FileReader fileReader = null;//使用处理流时必须要有节点流

        BufferedReader bufferedReader = null;

        try{

            fileReader = new FileReader("e:/java4android/users.txt");

            bufferedReader = new BufferedReader(fileReader);

            //String line = bufferedReader.readLine();

            //System.out.println(line);

            String line = null;

            while(true){

                line = bufferedReader.readLine();

                if(line == null){

                    break;

                }

                System.out.println(line);

            }

        }

        catch(Exception e){

            System.out.println(e);

        }

        finally{

            try{

                bufferedReader.close();

                fileReader.close();

            }

            catch(Exception e){

                System.out.println(e);

            }

        }

        

    }

 

}

编译运行

张三 F 20

李四 M 21

王五 F 22

赵六 M 23

2."装饰者(Decorator)模式"

假设要实现工人的管理系统。"工人"为父类,其子类有"水管工"和"木匠",A公司跟B公司都有水管工和木匠。假设一共有M家公司,这些公司都有N个工种的话,这就需要建立M*N个子类。这样做太复杂了,如何让继承体系变得简化一些呢?这就需要使用"装饰者"模式

现在有A公司跟B公司的木匠跟水管工,假设A公司的员工进门会说"你好"

Worker.java

interface Worker {

    publicvoid doSomeWork();

}

Carpenter.java

class Carpenter implements Worker {

    publicvoid doSomeWork(){

        System.out.println("修门窗");

    }    

}

Plumber.java

class Plumber implements Worker{

    publicvoid doSomeWork(){

        System.out.println("修水管");

    }

}

AWorker.java

class AWorker implements Worker{

    private Worker worker;

    public AWorker(Worker worker){

        this.worker = worker;

    }

    publicvoid doSomeWork(){

        System.out.println("你好");

        worker.doSomeWork();

        

    }

}

Test01.java

class Test01 {

    publicstaticvoid main(String args []){

        //生成一个水管工对象

        Plumber plumber = new Plumber();

//AWorker是装饰者,Plumber为被装饰者

        AWorker aWorker1 = new AWorker(plumber);

        aWorker1.doSomeWork();

    //AWorker是装饰者,Carpenter为被装饰者

        Carpenter carpenter = new Carpenter();

        AWorker aWorker2 = new AWorker(carpenter);

        aWorker2.doSomeWork();

    }

}

编译运行

你好

修水管

你好

修门窗

 

35_内部类和匿名内部类

主要内容:

  1. 什么是内部类?
  2. 内部类的使用方法
  3. 匿名内部类的使用方法

1.什么是内部类?

在类的内部定义类

A.java

class A {

    class B{

        

    }

}

 

编译完之后

A$B.class为内部类生成的类文件

2.内部类的使用方法

①使用内部类定义一个对象

A.java

class A {

    class B{

        

    }

}

 

Test.java

class Test {

    publicstaticvoid main(String args []){

        A a = new A();

        A.B b = new A().new B();

    }

}

内部类可以随意使用外部类所定义的成员变量

A.java

class A {

    inti;

    

    class B{

        intj;

        int funB(){

            intresult = i + j;

            returnresult;

        }

    }

}

在funB()中,使用了i是使用了外部类的i,可以用下边的例子证明

A.java

class A {

    inti;

    

    class B{

        intj;

        int funB(){

            intresult = i + j;

            returnresult;

        }

    }

}

 

Test.java

class Test {

    publicstaticvoid main(String args []){

        A a = new A();

        A.B b = a.new B();

        

        a.i = 3;

        b.j = 1;

        intresult = b.funB();

        System.out.println(result);

    }

}

编译运行

4

3.匿名内部类的使用方法

先看个例子

A.java

interface A {

    publicvoid doSomething();

}

AImpl.java

class AImpl implements A{

    publicvoid doSomething(){

        System.out.println("doSomething");

    }

}

 

B.java

class B {

    publicvoid fun(A a){

        System.out.println("B类的fun函数");

        a.doSomething();

    }

    

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        AImpl al = new AImpl();

        A a = al;

        

        B b = new B();

        b.fun(a);

    }

}

编译运行

B类的fun函数

doSomething

 

再看匿名类

A.java

interface A {

    publicvoid doSomething();

}

AImpl.java

class AImpl implements A{

    publicvoid doSomething(){

        System.out.println("doSomething");

    }

}

 

B.java

class B {

    publicvoid fun(A a){

        System.out.println("B类的fun函数");

        a.doSomething();

    }

    

}

 

Test.java

class Test {

    publicstaticvoid main(String args []){

        //AImpl al = new AImpl();

        //A a = al;

        

        B b = new B();

        b.fun(new A(){

            publicvoid doSomething(){

                System.out.println("匿名内部类");

            }

        });

    }

}

标注部分为对A接口的实现,因其没有名字,所以称为匿名类

new A(){

            publicvoid doSomething(){

                System.out.println("匿名内部类");

            }

        }

这部分代码生成了一个对象,这个对象就是你匿名类的对象

new一个借口,然后紧接着后边一个类来对这个接口进行实现

36_Java当中的线程

主要内容:

  1. 进程和线程
  2. 多线程程序运行模式
  3. 定义线程的方法

多线程与多进程

多进程:(进程是在各自独立的内存空间中运行

    在操作系统中能(同时)运行多个任务(程序)

多线程:(一个进程中的线程可以共享系统分派给这个进程的内存空间

    在同一应用程序中有多个顺序流(同时)执行

线程就是进程当中一个程序进行的流程

Android系统就是一个多进程系统,每启动一个软件就会启动一个进程。原则上来讲,一个软件只有一个进程,在进程下边又分成好多个线程

线程的执行过程

 

先生成线程,然后进入就绪状态后就准备开始运行了,就开始跟其他线程一起抢占CPU的执行时间,抢到CPU执行时间后进入运行状态,运行几步后可能CPU又被别的线程抢走了,这时候线程又进入就绪状态,过一会再抢到CPU又进入运行状态,直到线程执行完毕,进入死亡状态。线程在运行过程中可能进入阻塞状态,比如线程去网络上读取数据,结果网络上没有,等网络数据有了就会解除阻塞状态,又去抢占CPU。

Java是面向对象的,要用到线程就要有线程对象,要有线程对象就需要有线程类。

创建线程的第一种方法

方式1:

    定义一个线程类,它集成类Thread(由JDK提供)并重写其中的方法run(),方法run()称为线程体。

    由于Java只支持单继承,用这种方法定义的类不能在继承其他类。

FirstThread.java

class FirstThread extends Thread{

    publicvoid run(){

        for(inti=0;i<5;i++){

            System.out.println("FirstThread-->"+i);

        }

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        //生成线程类的对象

        FirstThread ft = new FirstThread();

        //启动线程

        ft.start();//Thread中继承得来的

        //ft.run();//千万不要这样写

    }

}

编译运行

FirstThread-->0

FirstThread-->1

FirstThread-->2

FirstThread-->3

FirstThread-->4

 

ft.start();一旦运行线程就进入就绪状态,程序中有三个线程:主函数main线程,ft线程,垃圾回收线程(可忽略)。从下边里例子就能看到

FirstThread.java

class FirstThread extends Thread{

    publicvoid run(){

        for(inti=0;i<5;i++){

            System.out.println("FirstThread-->"+i);

        }

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        //生成线程类的对象

        FirstThread ft = new FirstThread();

        //启动线程

        ft.start();//Thread中继承得来的

        //ft.run();//千万不要这样写,这样写相当调用函数了程序就只有一个mian线程了

        for(inti=0;i<5;i++){

            System.out.println("main-->"+i);

        }

    }

}

编译运行

main-->0

FirstThread-->0

main-->1

FirstThread-->1

main-->2

main-->3

main-->4

FirstThread-->2

FirstThread-->3

FirstThread-->4

37_Java当中的线程(二)

主要内容:

  1. 实现线程的第二种方法
  2. 控制线程的常用函数

1.实现线程的第二种方法(实际开发中一般都是用二种方法)

方式2:    

提供一个实现接口Runnable的类作为线程的目标对象,在初始化一个Thread类或者Thread子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体。

 

RunnableImpl.java

class RunnableImpl implements Runnable{

    publicvoid run(){

        for(int i=0;i<5;i++){

            System.out.println("Runnable-->"+i);

        }

    }

 

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        //生成一个Runnable接口实现类的对象

        RunnableImpl ri = new RunnableImpl();

    //生成一个Thread对象,并将Runnable接口实现类对象作为参数传递给改Thread对象

        Thread t = new Thread(ri);

        //通知Thread对象,执行start方法

        t.start();

        

    }

}

编译运行

Runnable-->0

Runnable-->1

Runnable-->2

Runnable-->3

Runnable-->4

2.控制线程的常用函数

中断线程:

—Thread.sleep()

—Thread.yield()

设置线程的优先级:

—getPriority()

—setPriority()

Thread.sleep() 设置休眠时间,休眠时间到了线程不是马上运行而是进入就绪状态,跟其他线程争到CPU时才运行

RunnableImpl.java

class RunnableImpl implements Runnable{

    publicvoid run(){

        for(inti=0;i<5;i++){

            System.out.println("Runnable-->"+i);

            if(i==3){

                try{

                    Thread.sleep(2000);//执行产生异常,所以采用try…catch

                }

                catch(Exception e){

                    System.out.println(e);

                }

            }

        }

    }

}

Thread.yield() 线程运行到这行代码,自动让出CPU,不代表当前线程不抢CPU了,而是再次与别的线程争取CPU

-getPriority() 得到优先级

-setPriority() 设置优先级

Test.java

class Test {

    publicstaticvoid main(String args []){

        //生成一个Runnable接口实现类的对象

        RunnableImpl ri = new RunnableImpl();

    //生成一个Thread对象,并将Runnable接口实现类对象作为参数传递给改Thread对象

        Thread t = new Thread(ri);

        t.setPriority(Thread.MAX_PRIORITY);

        //通知Thread对象,执行start方法

        //t.start();

        System.out.println(t.getPriority());

        t.setPriority(Thread.MIN_PRIORITY);

        System.out.println(t.getPriority());

    }

}

编译运行

10

1

线程最大优先级是10,最小优先级是1,可以使用Thread所提供的静态常量来设置线程的优先级。优先级越大,线程执行的概率越大

38_Java当中的线程(三)

主要内容:

  1. 多线程数据安全
  2. 同步线程的方法

1.多线程数据安全

MyThread.java

class MyThread implements Runnable{

    inti =100;

    publicvoid run(){

        while(true){

    //Thread.currentThread()获取当前代码正在哪个线程中运行,会反馈一个线程对象

            System.out.println(Thread.currentThread().getName()+i);

            i--;

            Thread.yield();

            if(i<0){

                break;

            }

        }

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        MyThread myThread = new MyThread();

        //生产了两个Thread对象,但是这两个Thread对象共用一个线程体

        Thread t1 = new Thread(myThread);

        Thread t2 = new Thread(myThread);

        //每一个线程都有名字,可以通过Thread对象的setName()方法设置线程名字,也可以使用getName方法获取线程的名字

        t1.setName("线程a");

        t2.setName("线程b");

        //分别启动两个线程

        t1.start();

        t2.start();

    }

}

编译运行

线程a100

线程b100

线程b98

线程a97

线程b96

线程a95

线程b94

线程a93

线程b92

……

线程a7

线程b6

线程a5

线程b4

线程a3

线程b2

线程a1

线程b1

前两行结果就出错了,结果应该是线程a100,线程b99….不可能出现线程a跟线程b都为100才对,这是线程同步错误,就是多线程共用一份数据的时候就会产生这种错误。A线程执行一半时b线程闯入执行就会出错。解决这个问题就要用到同步代码块

2.同步线程的方法

MyThread.java

class MyThread implements Runnable{

    inti =100;

    publicvoid run(){

        while(true){

            //this为同步锁,a线程拿到thisb线程想执行需拿到this否则需等待,不会//a线程执行一段代码时b代码闯入进行执行

            synchronized(this){

    //Thread.currentThread()获取当前代码正在哪个线程中运行,会反馈一个线程对象

                System.out.println(Thread.currentThread().getName()+i);

                i--;

                Thread.yield();

                if(i<0){

                    break;

                }

            }

        }

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        MyThread myThread = new MyThread();

        //生产了两个Thread对象,但是这两个Thread对象共用一个线程体

        Thread t1 = new Thread(myThread);

        Thread t2 = new Thread(myThread);

        //每一个线程都有名字,可以通过Thread对象的setName()方法设置线程名字,也可以使用getName方法获取线程的名字

        t1.setName("线程a");

        t2.setName("线程b");

        //分别启动两个线程

        t1.start();

        t2.start();

    }

}

编译运行

线程a100

线程a99

线程b98

线程a97

线程b96

线程b95

线程b94

线程b93

….

线程a5

线程b4

线程b3

线程b2

线程b1

线程b0

线程a-1

39_深入同步语法

主要内容:

  1. 深入synchronized关键字
  2. 同步方法

1.深入synchronized关键字

Service.java

class Service {

    publicvoid fun1(){

        synchronized(this){

            try{

                Thread.sleep(3*1000);

            }

            catch(Exception e){

                System.out.println(e);

            }

            System.out.println("fun1");

        }

    }

    publicvoid fun2(){

        synchronized(this){

            System.out.println("fun2");

        }

    }

}

MyThread1.java

class MyThread1 implements Runnable{

    private Service service;

    

    public MyThread1(Service service){

        this.service = service;

    }

    

    publicvoid run(){

        service.fun1();

    }

}

MyThread2.java

class MyThread2 implements Runnable{

    private Service service;

    

    public MyThread2(Service service){

        this.service = service;

    }

    

    publicvoid run(){

        service.fun2();

    }

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        Service service = new Service();

        Thread t1 = new Thread(new MyThread1(service));

        Thread t2 = new Thread(new MyThread2(service));

        

        t1.start();

        t2.start();

    }

}

编译运行

fun1

fun2

一旦某一线程获得了一个对象的同步锁,那么这个对象上所有其他同步的代码都不能被其他的线程执行,都需要等待同步锁被释放之后才能够执行,但是这个同步锁并不会影响其他的非同步的代码。比如Service.java改为

class Service {

    publicvoid fun1(){

        synchronized(this){

            try{

                Thread.sleep(3*1000);

            }

            catch(Exception e){

                System.out.println(e);

            }

            System.out.println("fun1");

        }

    }

    publicvoid fun2(){

        //synchronized(this){

            System.out.println("fun2");

        //}

    }

}

编译运行

fun2

fun1

2.同步方法

同步方法锁住的就是this

把Service.java改为

class Service {

    publicsynchronizedvoid fun1(){

        try{

            Thread.sleep(3*1000);

        }

        catch(Exception e){

            System.out.println(e);

        }

        System.out.println("fun1");

    }

    publicsynchronizedvoid fun2(){

        System.out.println("fun2");

    }

}

同步方法跟同步代码块的功能类似,同步代码块可以明确表达要锁住的对象,而同步方法锁住的就是this

40_Java当中的数组

主要内容:

  1. 数组的类型
  2. 数组的定义方法
  3. 数组的操作方法

1.数组的定义方法

//数组的静态声明法,arr的类型是整型数组

intarr [] = {5,2,7,9,0};也可以写为int [] arr = {5,2,7,9,0};

Test.java

class Test {

    publicstaticvoid main(String args []){

        //数组的静态声明法,arr的类型是整型数组

        intarr [] = {5,2,7,9,0};

        arr[3] = 10;

        System.out.println("arr数组的长度是"+arr.length);

        for(inti=0;i<arr.length;i++){

            System.out.println(arr[i]);

        }

    }

}编译运行

arr数组的长度是5

5

2

7

10

0

//数组的动态声明法,arr的类型是整型数组

intarr [] = newint[10];

chararr [] =newchar[10];

 

Test.java

class Test {

    publicstaticvoid main(String args []){

        //数组的静态声明法,arr的类型是整型数组

        //int arr [] = {5,2,7,9,0};

        //数组的动态声明法,arr的类型是整型数组

        intarr [] = newint[5];

        System.out.println("arr数组的长度是"+arr.length);

        for(inti=0;i<arr.length;i++){

            System.out.println(arr[i]);

        }

    }

}

编译运行

arr数组的长度是5

0

0

0

0

0

元素是int的数组默认值是0,元素就bool型的数组默认值是false,元素是char的数组默认值是空字符

2.二维数组定义方法

//二维数组的定义方法

intarr [][] = {{1,2,3},{4,5,6},{7,8}};

 

Test.java

class Test {

    publicstaticvoid main(String args []){

        //二维数组的定义方法

        intarr [][] = {{1,2,3},{4,5,6},{7,8}};

        

        //循环打印数组

        for(inti=0;i<arr.length;i++){

            for(intj=0;j<arr[i].length;j++){

                System.out.print(arr[i][j]);

            }

            System.out.println();

        }

    }

}

编译运行

123

456

78

 

 

//二维数组的动态定义方法

Int arr [][] =new int[3][5];

41_类集框架(一)

主要内容:

  1. 什么是类集框架?
  2. 集合的种类
  3. 类集框架的基础结构

什么是类集框架?

类集框架是一组类和接口

位于java.util包当中

主要用户存储和管理对象

主要分为三大类——集合、列表和映射

ArrayList里可以存放无限多对象

arrayList.add("a");//添加一个对象

arrayList.remove(0);//删除一个对象

Test.java

import java.util.List;

import java.util.ArrayList;;

publicclass Test {

    publicstaticvoid main(String args []){

        ArrayList<String> arrayList = new ArrayList<String>();

        

        arrayList.add("a");

        arrayList.add("b");

        arrayList.add("c");

        

        for(inti=0;i<arrayList.size();i++){

            String s = arrayList.get(i);

            System.out.println(s);            

        }

    }

}

编译运行

a

b

c

Test.java

import java.util.List;

import java.util.ArrayList;;

publicclass Test {

    publicstaticvoid main(String args []){

        ArrayList<String> arrayList = new ArrayList<String>();

        

        arrayList.add("a");

        arrayList.add("b");

        arrayList.add("c");

        arrayList.add("d");

        arrayList.remove(0);

        

        for(inti=0;i<arrayList.size();i++){

            String s = arrayList.get(i);

            System.out.println(s);            

        }

    }

}

编译运行

b

c

d

42_类集框架(二)

主要内容:

  1. Collection和Iterator接口
  2. Set与HashSet的使用方法

1.Collection接口

2.Set与HashSet的使用方法

Set本身是jdk提供的接口,继承了Collection接口,Collection里有的方法Set也都有。Set有个实现类叫HashSet

Test.java

import java.util.Set;

import java.util.HashSet;

publicclass Test {

    publicstaticvoid main(String args []){

        //HashSet<String> hashSet = new HashSet<String>();

        //Set<String> set = hashSet;//向上转型

        Set<String> set = new HashSet<String>();//等价于上边两行

        

        set.add("a");

        set.add("b");

        set.add("c");

        set.add("d");

        set.add("c");

        

        int i = set.size();

        System.out.println(i);

    }

}

编译运行

4

这说明Set里没有重复的对象

clear用法

Test.java

import java.util.Set;

import java.util.HashSet;

publicclass Test {

    publicstaticvoid main(String args []){

        //HashSet<String> hashSet = new HashSet<String>();

        //Set<String> set = hashSet;//向上转型

        Set<String> set = new HashSet<String>();

        

        set.add("a");

        set.add("b");

        set.add("c");

        set.add("d");

        set.add("c");

        

        inti = set.size();

        System.out.println("clear之前set对象的长度是"+i);

        set.clear();

        intj = set.size();

        System.out.println("clear之后set对象的长度是"+j);

    }

}

编译运行

clear之前set对象的长度是4

clear之后set对象的长度是0

 

remove用法

Test.java

import java.util.Set;

import java.util.HashSet;

publicclass Test {

    publicstaticvoid main(String args []){

        //HashSet<String> hashSet = new HashSet<String>();

        //Set<String> set = hashSet;//向上转型

        Set<String> set = new HashSet<String>();

        

        set.add("a");

        set.add("b");

        set.add("c");

        set.add("d");

        set.add("c");

        

        inti = set.size();

        System.out.println("remove之前set对象的长度是"+i);

        set.remove("a");

        intj = set.size();

        System.out.println("remove之后set对象的长度是"+j);

    }

}

编译运行

remove之前set对象的长度是4

remove之后set对象的长度是3

isEmpty()用法

import java.util.Set;

import java.util.HashSet;

publicclass Test {

    publicstaticvoid main(String args []){

        //HashSet<String> hashSet = new HashSet<String>();

        //Set<String> set = hashSet;//向上转型

        Set<String> set = new HashSet<String>();

        booleanb1 = set.isEmpty();

        System.out.println(b1);

        set.add("a");

        set.add("b");

        set.add("c");

        set.add("d");

        set.add("c");

        

        booleanb2 = set.isEmpty();

        System.out.println(b2);

        inti = set.size();

        System.out.println("remove之前set对象的长度是"+i);

        set.remove("a");

        intj = set.size();

        System.out.println("remove之后set对象的长度是"+j);

    }

}

编译运行

true

false

remove之前set对象的长度是4

remove之后set对象的长度是3

3.Iterator迭代器

Iterator迭代器,可以用于取出Set中的对象

Iterator <--- Collection <--- Set <--- HashSet

hasNext() 判断迭代器中有没有下一个对象,返回值是boolean值

next() 返回下一个对象

Test.java

import java.util.Set;

import java.util.HashSet;

import java.util.Iterator;

public class Test {

    public static void main(String args []){

        //HashSet<String> hashSet = new HashSet<String>();

        //Set<String> set = hashSet;//向上转型

        //Iterator <--- Collection <--- Set <--- HashSet

        //hasNext() next()

 

        Set<String> set = new HashSet<String>();

 

        set.add("a");

        set.add("b");

        set.add("c");

        set.add("d");

        set.add("c");

        

        //调用Set对象的Iterator方法,会生成一个迭代器对象,该对象用于遍历整个Set

        Iterator<String> it = set.iterator();

        while(it.hasNext()){

            String s = it.next();

            System.out.println(s);

        }

 

    }

}

编译运行

a

b

c

d

Iterator迭代器,也可以用于取出List中的对象,但是List通过下标来取更方便

Iterator <--- Collection <--- List <--- ArrayList

43_类集框架(三)

主要内容:

  1. MapHashMap的使用方法
  2. JDK帮助文档的使用方法

Test.java

import java.util.Map;

import java.util.HashMap;

 

publicclass Test {

    publicstaticvoid main(String args []){

        HashMap<String,String> hashMap = new HashMap<String,String>();

        Map<String,String> map = hashMap;

        map.put("1", "a");

        map.put("2", "b");

        map.put("3", "c");

        map.put("4", "d");

        map.put("3", "e");//键是一样的,后边的值会覆盖前边的值

        int i = map.size();

        System.out.println(i);

        //取值

        String s = map.get("3");

        System.out.println(s);

    }

}

编译运行

4

e

44_equals函数的作用

主要内容:

  1. equals函数在什么地方
  2. equals函数的作用
  3. 复写equals函数的方法

1.equals函数在什么地方

equals函数在object类中,object又是所有类的父类,即所有的类都继承了equals函数

2.equals函数的作用

"=="作用是判断两个引用是否指向堆内存中的同一块地址

User.java

class User {

    String name;

    intage;

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User u1 = new User();

        User u2 = new User();

        User u3 = u1;

        

        booleanb1 = u1 == u2;

        boolean b2 = u1 == u3;

        System.out.println(b1);

        System.out.println(b2);

    }

}

编译运行

false

true

 

equals()用于判断两个对象的内容是否相等

User.java

class User {

    String name;

    intage;

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User u1 = new User();

        User u2 = new User();

        

        booleanb1 = u1.equals(u2);

        System.out.println(b1);

    }

}

编译运行

false

3. 复写equals函数的方法

Java jdk当中equals的定义为

public boolean equals(Object obj) {

return (this == obj);

}

通过定义可以看出equals与==的作用一样。实际上jdk定义的equals并不是让用户直接用的,而是让用户复写后用的。复写的原则是下边的两条

User.java

class User {

    String name;

    intage;

    

    publicboolean equals(Object obj){

        //如果thisobj指向堆内存中同一个对象,那么肯定相等,后边就不用判断了

        if(this==obj){//this属于User类型

            returntrue;

        }

        //判断obj是否属于User类型

        booleanb = objinstanceof User;

        if(b){

            User u = (User)obj;//向下转型

            //比较基本数据类型的成员变量用"==",引用数据类型成员变量用equals,

//nameString类型是引用数据类型,判断内容相等调用equals(这里的equals属于Java jdk //String中定义好的)

            if(this.age == u.age && this.name.equals(u.name)){

                returntrue;

            }

            else{

                returnfalse;

            }

            

        }

        else{

            returnfalse;

        }

    }

 

}

Test.java

class Test {

    publicstaticvoid main(String args []){

        User u1 = new User();

        User u2 = new User();

        User u3 = new User();        

        

        u1.name = "zhangsan";

        u1.age = 12;

        

        u2.name = "lisi";

        u2.age =12;

        

        u3.name = "zhangsan";

        u3.age = 12;

        

        System.out.println(u1.equals(u2));

        System.out.println(u1.equals(u3));

    }

}

编译运行

false

true

实际开发中很少自己动手复写equals,一般是借助开发工具生成,本节课只是介绍equals的作用及如何复写equals

45_hashCode()与toString()

主要内容:

  1. hashCode()的作用
  2. hashCode()的实现方法
  3. toString()的作用
  4. toString()的实现方法

hashCode()作用与实现方法

可以根据散列值找到数据存储位置

hashCode()方法存在于object中,也就是所有的类都拥有hashCode()方法,hashCode()方法没有参数,返回值是int。调用某一个对象的hashCode方法之后,会产生一个这个对象的哈希码。Sun公司规定的equals跟hashCode的写法有一条规定:如果两个对象用eauqls相比是相等的,那么这两个对象分别调用hashCode产生的哈希码也应该是相等的,这也是复写hashCode()的原则。hashCode()被广泛应用到类集框架中

 

User.java

class User {

    String name;

    intage;

    

    public User(){        

    }    

    public User(String name,int age){

        this.name = name;

        this.age =age;

    }

 

    publicboolean equals(Object obj){

        if(this==obj){

            returntrue;

        }

        booleanb = objinstanceof User;

        if(b){

            User u = (User)obj;//向下转型

            //比较基本数据类型的成员变量用"==",引用数据类型成员变量用equals

            if(this.age == u.age && this.name.equals(u.name)){

                returntrue;

            }

            else{

                returnfalse;

            }

            

        }

        else{

            returnfalse;

        }

    }

 

}

Test.java

import java.util.*;

class Test {

    publicstaticvoid main(String args []){

        User u = new User("zhangsan",12);

        

        HashMap<User,String> map = new HashMap<User,String>();

        map.put(u, "abc");

        

        String s = map.get(new User("zhangsan",12));

        System.out.println(s);

    }

}

编译运行

null

本来应该打印键的值"abc"。map根据键寻找值。实际上是根据键的hashCode()值来决定的。这里运行结果是null不是"abc"是因为采用的是默认的hashCode来实现的。

所以应该复写hashCode来实现想要的结果

User.java

class User {

    String name;

    intage;

    

    public User(){        

    }    

    public User(String name,intage){

        this.name = name;

        this.age =age;

    }

    publicboolean equals(Object obj){

        if(this==obj){

            returntrue;

        }

        booleanb = objinstanceof User;

        if(b){

            User u = (User)obj;//向下转型

            //比较基本数据类型的成员变量用"==",引用数据类型成员变量用equals

            if(this.age == u.age && this.name.equals(u.name)){

                returntrue;

            }

            else{

                returnfalse;

            }

            

        }

        else{

            returnfalse;

        }

    }

    publicint hashCode(){

        intresult = 17;//此处为正的质数

        

        result = 31*result + age;

        result = 31*result + name.hashCode();

        returnresult;

    }

}

Test.java

import java.util.*;

class Test {

    publicstaticvoid main(String args []){

        User u =new User("zhangsan",12);

        

        HashMap<User,String> map = new HashMap<User,String>();

        map.put(u, "abc");

        String s = map.get(new User("zhangsan",12));

        System.out.println(s);

    }

}

编译运行

abc

此处复写的hashCode()实际开发中很少自己写,一般通过开发工具来生成,了解下 复写方法即可。

toString()作用与实现方法

toString()方法存在于object中,也就是所有的类都拥有toString ()方法。

Test.java

import java.util.*;

class Test {

    publicstaticvoid main(String args []){

        User u =new User("zhangsan",12);

        System.out.println(u);//会调用utoString()产生字符串,再打印

    }

}

编译运行

User@aa9c71b9

这是默认的toString()方法产生的结果

下边自己复写toString()方法,复写原则:把成员变量的值打印出来就行

User.java

class User {

    String name;

    intage;

    public User(){        

    }    

    public User(String name,intage){

        this.name = name;

        this.age =age;

    }

    publicboolean equals(Object obj){

        if(this==obj){

            returntrue;

        }

        booleanb = objinstanceof User;

        if(b){

            User u = (User)obj;//向下转型

            //比较基本数据类型的成员变量用"==",引用数据类型成员变量用equals

            if(this.age == u.age && this.name.equals(u.name)){

                returntrue;

            }

            else{

                returnfalse;

            }            

        }

        else{

            returnfalse;

        }

    }

    publicint hashCode(){

        intresult = 17;//此处为正的质数

        result = 31*result + age;

        result = 31*result + name.hashCode();

        returnresult;

    }

    public String toString(){

        String result ="age:"+ age + "," + "name:" + name;

        return result;

    }

}

Test.java

import java.util.*;

class Test {

    publicstaticvoid main(String args []){

        User u =new User("zhangsan",12);

        System.out.println(u);

    }

}

编译运行

age:12,name:zhangsan

 

本课的三个方法了解一下就行,不用大量练习,回头学习了Eclipse工具的使用方法,可以用Eclipse工具可以自动复写这三个方法。

46_开发工具之Eclipse(一)

主要内容:

  1. 什么是Eclipse
  2. Eclipse的基本概念
  3. Eclipse界面简介

Eclipse基本概念

工作区(workspace)

项目(Project)

47_开发工具之Eclipse(二)

主要内容:

  1. 在Eclipse当中创建Java项目
  2. Java项目的目录结构
  3. 编译运行Java项目
  4. Eclipse的错误提示

 

Eclipse不用手动编译,程序保存完后自动编译

Eclipse新建一个类,一个接口,错误提示,调试错误

48_开发工具之Eclipse(三)

主要内容:

  1. Java代码编辑
  2. Eclipse代码生成工具

 

Eclipse部分快捷键

 

  alt + /             代码助手功能

删除、复制、粘贴、剪切 基本操作

ctrl + d            删除一行代码

ctrl + z         撤销(undo)操作

ctrl + y        redo操作,重新执行之前的操作

生成构造函数,代码区右键--->source--->Generate Construtor using Fields

生成两个参数的构造函数,生成位置在成员变量age之后

生成三个参数的构造函数,生成位置在两个参数构造函数之后

toString()的自动生成,右键---> source--->Generate toString()

hashCode() and equals()的自动生成,右键---> source--->Generate hashCode() and equals()

 

alt + shift + s     打开source菜单

ctrl + shift + /    块注释(/* */), ctrl + shift + \    取消块注释(/* */)

ctrl + /            注释或取消注释代码(单行注释)

49_开发工具之Eclipse(四)

主要内容:

Java代码的重构

 

代码重构

  1. 重构可以改善软件的设计
  2. 重构可以让软件更加容易理解
  3. 重构可以协助寻找bugs
  4. 重构可以提升开发速度

修改名字,比如Student.java改为Students.java,右键Students.java--->Refactor--->Rename

移动,比如将Student.java移动到别的包中, 右键Students.java--->Refactor--->Move

修改方法的名称,比如将walk()方法的名称修改,右键walk()--->Refactor--->Change Method     Signature

把方法放到父类里边去,比如将walk()放到父类里,右键walk()--->Refactor--->Pull Up

把方法放到子类里边去,比如将walk()放到父类里,右键walk()--->Refactor--->Pull Down

把代码抽取成函数,选择要抽取的代码右键--->Refactor--->Extract Method

50_综合练习(一)

主要内容:

  1. 综合练习目标
  2. 综合练习需求

综合练习目标

  1. 复习Java基本语法
  2. 熟练掌握Java开发常用API
  3. 尝试建立面向对象思想

综合练习基本需求

  1. 接收用户的命令行输入
  2. 以文件为基础完成数据的增删改查操作

51_综合练习(二)

主要内容:

综合练习模块划分

UI模块用于跟用户进行交互,接收用户输入,返回结果

文件IO模块相当于数据库作用

数据验证模块用于验证用户所输入的数据是否是合法的,比如输入年龄为负数时就不合法

逻辑模块用于业务逻辑的运算

52_定义输入输出格式

主要内容:

  1. 用户的输入格式
  2. 应用程序的输出格式
  3. 关于提示信息的思考

53_综合练习(四)

主要内容:

  1. 资源文件的作用
  2. 资源文件的格式与访问
  3. 主循环的设计

first.properties

key1=value1

key2=value2

Test.java

package org.marsdroid;

import java.io.File;

import java.io.FileInputStream;

import java.util.Properties;

import java.io.InputStream;

public class Test {

    public static void main(String[] args) {

        Properties properties = new Properties();

        String projectPath = System.getProperty("user.dir");

        System.out.println(projectPath);

        //separator在UNIX系统中用的是"/",在WINDOWS下用的是"\"

        String propertiesPath = projectPath + File.separator +"resources" + File.separator + "first.properties";

        try{

            InputStream in = new FileInputStream(propertiesPath);

            properties.load(in);

            System.out.println(properties.get("key1"));

            System.out.println(properties.get("key2"));

        }

        catch(Exception e){

            e.printStackTrace();

        }

    }

}

编译运行

D:\Program Files\Android\workspace\53

value1

value2

1 0
原创粉丝点击