Java4Android课程介绍
什么是Java考古学
Java发展史
总结
书写源代码、编译、运行
在命令行窗口中,通过cd进入所写的java目录(假设所写的java程序为HelloWorld.java),运行
javac HelloWorld.java 进行编译
java HelloWorld 进行运行
1.环境变量通常是指在操作系统当中,用来指定操作系统运行时需要的一些参数
2.环境变量通常为一系列的键值对
3.Path环境变量是操作系统外部命令搜索路径
4.classpath环境变量是类文件搜索路径
5.编译是把源代码翻译成计算机可识别的代码,
6.JRE是JAVA Runtime Environment即Java运行环境
7.编译器是把源文件翻译成虚拟机能识别的代码,JVM(JAVA虚拟机)是把.class类文件翻译成操作系统可识别的代码
1.计算机是一种极度精确的机器;
2.要将信息存储在计算机当中,就必须指明信息存储的位置和所需要的内存空间;
3.在Java编程语言当中,使用声明语句来完成上述的任务;
变量的声明方法:
变量命名需符合驼峰命名法:1、变量名应该用有意义的英文单词;2、变量名如果只有一个单词,则所有的字母小写;3、变量名如果由多个英文单词组成,则从第二个单词开始首字母大写
主要内容:
1.Java数据类型分类
2.boolean类型变量特征
3.char类型变量特征
4.数值型变量特征
①boolean类型适用于逻辑运算,一般用于程序流程控制
②在Java当中boolean类型只有两种取值可能-----true和false
eg:
boolean b = false;
①char类型变量用于表示通常意义上的字符;
②字符是由单引号括起来的单个字符;
eg:
char c = 'a';
③Java字符使用Unicode字符集
①在计算机中所有的数据都需要使用二进制的数字表示;
②类似于a,b,c无法直接用二进制表示,所以就将所有常见的符号进行编号;
③标准ASCII码使用7位2进制数来表示字符;
④7位2进制数可以表示所有的数字、大小写字母以及一些常见的符号(例如!,@,#$);
①Unicode为每种语言的每个字符设定了统一并且唯一的二进制码;
②Unicode使用数字0-0x10FFFF来表示字符,最多允许有1114112个字符;
③乱码的产生是存这个字的字符集跟取这个数的字符集不一样;
④Unicode中一个中文字符跟一个英文字符所占的空间是一样的;
Exerc01.java
public class Exerc01 {
public static void main(String args []){
boolean b = true;
System.out.println(b);
}
}
编译运行
true
Exerc02.java
public class Exerc02 {
public static void main(String args []){
char c = 'a';
//char c = '中';
System.out.println(c);
}
}
编译运行
a
Exerc03.java
public class Exerc03 {
public static void main(String args []){
byte b = 0;
short s = 0;
int i = 0;
long l = 0;
float f = 0;
double d = 0;
//float f1 = 0.1; //可能损失精度
float f1 = 0.1F; //正确
//int j = 0.5*10; //可能损失精度
double j = 0.5*10 + 4 + 1; //正确
//byte k = b+0; //可能损失精度
byte k = (byte)(b+0); //正确
}
}
字面量:
整数字面量为整型(int)
小数字面量为双精度浮点型(double)
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
表达式的值:
对表达式中操作数进行运算得到的结果称为表达式的值
表达式的类型:
表达式的值的数据类型即为表达式的类型
程序运行流程的分类:顺序结构;分支结构;循环结构
default用[]括起来表示其在程序中可有可无,实际程序中用到default时不需要[]
练习目标:熟悉if…else…结构的使用方法
步骤:
Test01.java
public class Test01 {
public static void main(String args []){
int score = 90;
if(score > 85 && score <= 100){
System.out.println("成绩为优");
}
else if(score > 75 && score <=85){
System.out.println("成绩为良");
}
else if(score > 60 && score <=75){
System.out.println("成绩为中");
}
else if(score <= 60){
System.out.println("成绩为差");
}
else if(score > 100 && score < 0){
System.out.println("成绩不在正常范围内");
}
}
}
步骤:
Test02.java
public class Test02 {
public static void main(String args []){
//'a'代表石头,'b'代表剪子,'c'代表布
char play1 = 'a';
char play2 = 'b';
if(play1 == 'a' && play2 == 'a'){
System.out.println("平");
}
else if(play1 == 'a' && play2 == 'b'){
System.out.println("play1赢");
}
else if(play1 == 'a' && play2 == 'c'){
System.out.println("play2赢");
}
else if(play1 == 'b' && play2 == 'a'){
System.out.println("play2赢");
}
else if(play1 == 'b' && play2 == 'b'){
System.out.println("平");
}
else if(play1 == 'b' && play2 == 'c'){
System.out.println("play1赢");
}
else if(play1 == 'c' && play2 == 'a'){
System.out.println("play1赢");
}
else if(play1 == 'c' && play2 == 'b'){
System.out.println("paly2赢");
}
else if(play1 == 'c' && play2 == 'c'){
System.out.println("平");
}
}
}
for循环执行过程
for(int i = 0; i < 10; i++){
System.out.println(i);
}
while循环执行过程:
while (i < 10) {
System.out.println(i);
i++;
}
目标:熟悉java当中的for循环使用方法
步骤:
1、定义一个类,名为TestPrimNumber;
2、在类当中定义函数;
3、用for循环打印出所有在100——200之间的素数;
用for循环当中,每当循环执行一次,就判断循环变量的值是否为素数,如果是,就将循环变量的当前值打印出来;
判断n是否为素数方法:首先用2除n,如果除不尽,再用3除n,一次类推,如果从2到n-1,都无法整除n,那么n就为素数。
TestPrimNumber.java
class TestPrimeNumber{
public static void main(String args []){
for(int i = 100 ; i < 201 ; i++ ){
boolean b = false;
for(int j = 2 ; j < i-1;j++ ){
int k = 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{
public static void main(String args[]){
for(int i = 1; i < 5 ; i++){
for(int j = 0 ; j < 4 - i ; j++ ){
System.out.print(" ");
}
for(int k = 0; k < i ; k++){
System.out.print("* ");
}
System.out.println("");
}
}
}
(注:print如果不加—ln代表不用换行,加—ln代表需要换行,System.out.println("")这语句代表换行)
首先确定谁来做,其次确定怎么做;
首先考虑整体,其次考虑局部;
首先考虑抽象,其次考虑具体。
总结:不要认为掌握了一门面向对象语言就是掌握了面向对象;习惯于将面向对象与现实世界做比较
class 类名
{
属性;
方法;
}
属性也叫成员变量,主要用于描述类的状态;方法也叫成员方法,主要用于描述类的行为。
格式:类名 对象名=new 类名();
例如:Dog dog=new Dog();
对象的本体放在堆内存中,对象的名在栈内存中
例如Dog d=new Dog();这行代码的运行过程如下:
Dog d在栈内存中创建了一个Dog的引用;执行new Dog ()创建了一个Dog的对象,而对象本身放在堆内存中,new用来在堆内存中开辟一块空间放真正的对象,执行new Dog()在堆内存中开辟一块空间并将生成的Dog类型的对象放在这块空间里。所以说真正的对象在堆内存中,d只是指向对象的引用。注意:d不是对象,只是代表了对象。
类与对象的关系:类是抽象的概念,对象是具体的个体。
使用对象调用变量和函数:
例如定义Dog类
Dog.java
class Dog{
String name;
int age;
String color;
void jump(){
System.out.println("jump");
}
}
然后生成类的对象
Test.java
class Test{
public static void 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{
public static void main(String args []){
Dog d1= new Dog();
Dog d2= new Dog();
d1.name="旺财";;
d2.name="四喜";
d1.jump();
d2.jump();
}
}
修改一个对象例如d1的属性是不会影响d2的属性的
可以不定义对象的引用名称,而直接调用这个对象的方法。这样的对象叫做匿名对象,例如:
new Dog().jump();
匿名对象都是一次性的对象,因为没有名字,用完就找不到了
class A {
void funA(){
System.out.println("没有参数的funA函数");
}
void funA(int i){
System.out.println("拥有一个整型参数的funA函数");
}
}
这俩函数构成了重载关系:第一这俩函数在同一个类中,第二这俩函数函数名相同,第三参数列表不同。调用哪一个funA关键看传递的参数
重载的定义
class A {
A(){
}
void funA(){
System.out.println("没有参数的funA函数");
}
void funA(int i){
System.out.println("拥有一个整型参数的funA函数");
}
}
构造函数特征:没有返回值类型的定义,函数名必须跟类名相同
但是类中没有构造函数为什么也能用构造函数呢?因为编译器在编译源文件时会检查类中是否拥有构造函数,没有的话会自动加一个无参数且方法体为空的构造函数。如果类中已有构造函数,编译器就不会添加参数为空的构造函数。
构造函数作用:使用new调用构造函数可以生成对象;可以自己编写构造函数为成员变量赋初始值
Person.java
public class Person {
Person(){
}
Person(String n,int a){
name = n;
age = a;
}
String name;
int age;
}
Test.java
class Test {
public static void main(String args[]){
Person person1 = new Person("zhangsan",10);
Person person2 = new Person("lisi",20);
System.out.println("person1的name是"+person1.name+"age是"+person1.age);
System.out.println("person2的name是"+person2.name+"age是"+person2.age);
}
}
主要内容:
Person.java
class Person {
String name;
void talk(){
System.out.println("my name is "+this.name);
}
}
Test.java
class Test {
public static void 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.name的name代表成员变量的name,如果省略this的话代表参数name
this代表了调用函数的那个对象,如p1.talk(),p1调用了talk(),this就代表了p1。就像是中文中的"我"。张三说"我"时,"我"字代表张三;李四说"我"时,"我"代表李四。
Person.java
class Person {
String name;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String s1,int a,String s2){
name = s1;
age = a;
address = s2;
}
void talk(String name){
System.out.println("my name is "+this.name);
}
}
构造函数这样写没问题,但是调用时容易乱,应该如下写
Person(String name,int age,String address){
this.name = name;
this.age = age;
this.address = address;
}
this.name代表成员变量,等号后边的name代表参数
现在的构造函数是对Person的三个成员变量都赋值,有的时候只需要对两个成员变量赋值,再定义如下的构造函数能实现功能,但是显得重复了。
Person.java
class Person {
String name;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String name,int age){
this.name = name;
this.age = age;
}
Person(String name,int age,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;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String name,int age){
this.name = name;
this.age = age;
}
Person(String name,int age,String address){
this(name,age);//在构造函数中调用Person(String name,int age)
this.address = address;
}
void talk(String name){
System.out.println("my name is "+this.name);
}
}
在一个构造函数中使用this调用另一个构造函数,必须注意的是在一个构造函数里this必须是第一条语句,这样的话在一个构造函数里只能调用同类的另一个构造函数,不能调用同类的另两个构造函数,也就是不能有如下写法
class Person {
String name;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String name,int age){
this.name = name;
this.age = age;
System.out.println("两个参数的构造函数");
}
Person(String name,int age,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;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String name,int age){
this();
this.name = name;
this.age = age;
System.out.println("两个参数的构造函数");
}
Person(String name,int age,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;
int age;
String address;
Person(){
System.out.println("无参数的构造函数");
}
Person(String name,int age){
this();
this.name = name;
this.age = age;
System.out.println("两个参数的构造函数");
}
Person(String name,int age,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 {
public static void main(String args []){
Person p1 = new Person("zhangsan",20,"beijing");
}
}
运行结果
无参数的构造函数
两个参数的构造函数
三个参数的构造函数
主要内容:
可以使用类名来调用(也可以用对象来调用),比如
Person.java
class Person {
static int i;
}
Test.java
class Test {
public static void 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;
P1跟p2使用同一个成员变量,也就是说所有的对象使用的成员变量的值都是同一份
如
Person.java
class Person {
static int i;
}
Test.java
class Test {
public static void 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
可以使用类名来调用,比如
Person.java
class Person {
static void fun(){
System.out.println("我是静态函数");
}
}
Test.java
class Test {
public static void 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;
static void talk(){
System.out.println("my name is"+name);
}
}
注意:此处不能用this.name因为静态函数调用直接用"类名.函数"如Person.fun(); 这样就不存在调用函数的那个对象的问题,所以不能用this,而直接加name又解释不通,所以不能这样用。
但是如果name这个变量是静态的,如下写法就可以了
Person.java
class Person {
static String name;
static void talk(){
System.out.println("my name is "+name);
}
}
Test.java
class Test {
public static void main(String args []){
Person.name = "zhangsan";
Person.talk();
}
}
运行结果
my name is zhangsan
静态代码块无需调用,只要类中含有静态代码块,装载类的时候就会调用静态代码块。静态代码块的主要作用就是为静态变量赋值
Person.java
class Person {
static{
System.out.println("静态代码块");
}
static String name;
static void talk(){
System.out.println("my name is "+name);
}
}
Test.java
class Test {
public static void main(String args []){
Person.name = "zhangsan";
Person.talk();
}
}
运行结果
静态代码块
my name is zhangsan
总结:
主要内容:
在现实世界中,继承就是儿子得到了老子的东西;在面向对象的世界中,继承就是一个类得到了另外一个类当中的成员变量和成员方法。
Java中只支持单继承,不允许多继承。一个子类只允许继承一个父类,一个父类可以拥有多个子类。
Person.java
class Person {
String name;
int age;
void eat(){
System.out.println("吃饭");
}
void introduce(){
System.out.println("我的名字是"+name+",我的年龄是"+age);
}
}
Student.java
class Student extends Person{
}
Test.java
class Test {
public static void main(String args []){
Student student = new Student();
student.name = "张三";
student.age = 16;
student.eat();
student.introduce();
}
}
吃饭
我的名字是张三,我的年龄是16
Student继承了Person的成员变量和成员函数,还可以拥有自己的成员变量和成员函数
class Student extends Person{
int grade;
void study(){
System.out.println("学习");
}
}
eg:
Person.java
class Person {
String name;
int age;
void eat(){
System.out.println("吃饭");
}
void introduce(){
System.out.println("我的名字是"+name+",我的年龄是"+age);
}
}
Student.java
class Student extends Person{
int grade;
void study(){
System.out.println("学习");
}
}
Test.java
class Test {
public static void main(String args []){
Student student = new Student();
student.name = "张三";
student.age = 16;
student.grade = 3;
student.eat();
student.introduce();
student.study();
}
}
运行结果
吃饭
我的名字是张三,我的年龄是16
学习
如果两个类或更多的类拥有共同的成员变量和成员函数,就可以把这些成员变量和成员函数放到父类里边去,也就是重复的代码都放到父类去,然后这子类去继承这个父类。今天这些共同的代码需要修改时,只需要在父类中进行修改即可。
使用继承是为了减少重复代码,另外子类还可以在继承父类的基础上进行扩展
子类可以继承父类的成员变量和成员函数,但是不能继承父类的构造函数
主要内容:
Person.java
class Person {
String name;
int age;
Person(){
System.out.println("Person的无参数构造函数");
}
Person(String name,int age){
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 {
public static void main(String args []){
Student student = new Student();
}
}
运行结果
Person的无参数构造函数
Student的无参数构造函数
在子类的构造函数中,必须调用父类的构造函数,无明确调用父类构造函数时,编译器会自动加一行Super();用于调用父类中无参数的构造函数,如下
class Student extends Person{
int grade;
Student(){
Super();
System.out.println("Student的无参数构造函数");
}
}
Student从父类中继承了两个成员变量,自身有一个成员变量,要为三个成员变量赋值如果写成如下的构造函数的话,会显得跟父类中的构造函数重复
Student.java
class Student extends Person{
int grade;
Student(){
System.out.println("Student的无参数构造函数");
}
Student(String name,int age,int grade){
this.name = name;
this.age = age;
this.grade = grade;
}
}
为了避免重复,可以使用supper调用父类中的构造函数,具体调用父类中的哪个构造函数由super后边的参数来决定,完整程序如下
Person.java
class Person {
String name;
int age;
Person(){
System.out.println("Person的无参数构造函数");
}
Person(String name,int age){
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的无参数构造函数");
}
Student(String name,int age,int grade){
super(name,age);//一定要是这个函数的第一条语句,跟this一个道理
this.grade = grade;
}
}
Test.java
class Test {
public static void 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
主要内容:
复写(override)也成覆盖或重写:①在具有父子关系的两个类当中;②父类和子类各有一个函数,这两个函数的定义(返回值类型、函数名和参数列表)完全相同。
下边的例子,标黄的部分构成了函数的复写
Person.java
class Person {
String name;
int age;
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 {
public static void main(String args []){
Student s= new Student();
s.name = "张三";
s.age = 20;
s.address = "北京";
s.introduce();
}
}
运行结果
我的性命是张三我的年龄是20
我的家在北京
在函数的复写例子中两个函数存在重复,这就可以采用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();
}
主要内容:
向上转型-------将子类的对象赋值给父类的引用,现实生活中比如笔记本电脑属于电脑,茶杯属于杯子。比如下边的例子:Student是Person的子类,把一个Student类型的对象s赋值给一个Person类型的引用p
下边的例子编译会出错
Person.java
class Person {
String name;
int age;
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 {
public static void main(String args []){
Student s = new Student();
Person p = s;
p.name = "张三";
p.age = 20;
p.address = "北京";
}
}
p.address = "北京";这样用是错误的,一个引用能够调用哪些成员(变量和函数),取决于这个引用的类型
将Test.java改为如下
class Test {
public static void 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。一个引用调用的是哪一个方法取决于这个引用所指向的对象
向下转型--------将父类的对象赋值给子类的引用
向下成功的前提是先把一个对象向上转型,然后再把对象向下转型转回来,如下
Test.java
class Test {
public static void main(String args []){
//正确的向下转型
Person p = new Student();
Student s = (Student)p;
//错误的向下转型
//Person p = new Person();
//Student s = (Student)p;
}
}
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 {
public static void 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 {
public static void main(String args []){
int flag = 1;
if(flag==0){
HPPrinter hpPrinter = new HPPrinter();
hpPrinter.open();
hpPrinter.print("abc");
hpPrinter.close();
}
else if(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 {
public static void main(String args []){
int flag = 1;
if(flag==0){
HPPrinter hpPrinter = new HPPrinter();
hpPrinter.open();
hpPrinter.print("abc");
hpPrinter.close();
}
else if(flag==1){
CanonPrinter cannonPrinter = new CanonPrinter();
cannonPrinter.open();
cannonPrinter.print("abc");
cannonPrinter.close();
}
}
}
运行结果
Open
print-->abc
clean
close
这时就比较简单了,修改代码的代价就小了,因为我们把重复代码集中到父类中去了,新建一个打印机的类去继承Printer就行
主要内容:
什么是抽象函数
只有函数的定义,没有函数体的函数被称为抽象函数:
abstract void fun();
<