----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
1.基本知识
java是一门面向对象的语言.面向对象的特点是:封装/继承/多态.
面向过程:把大问题分解成小问题,再把小问题分解成沙粒状的问题,然后把每个沙粒状的问题逐一处理,问题也就解决了。
面向对象:来自我们的客观世界!找到处理问题所需的对象,然后组织对象,调用对象的功能来解决问题。
封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
封装原则:
将不需要对外提供的内容都隐藏起来。
把属性都隐藏,提供公共方法对其访问。
练习:实现一个Time类(hour/minute/second)/show(),
class TimeTest//测试自己定义的时间类
{
public static void main(String[] args)
{
MyTime mt=new MyTime();
mt.setHour(3);
mt.setMinute(13);
mt.setSecond(6);
mt.show();
MyTime mt1=new MyTime(12,4,24);
mt1.show();
}
}
/**
自己定义的一个时间类,对外提供了显示当前时间的方法
@author 王震阳
@version 1.0
*/
class MyTime//自己定义一个时间类
{
private int hour;
private int minute;
private int second;
MyTime(){}
MyTime(int hour,int minute,int second)
{
if((hour<24&&hour>=0)&&(minute>=0&&minute<60)&&(second>=0&&second<60))
this.hour=hour;
this.minute=minute;
this.second=second;
}
//封装hour
public void setHour(int hour)
{
if(hour>=0&&hour<24)
this.hour=hour;
else
{
System.out.println("您设置的时间: "+hour+"非法");
System.out.println("请设置一个[0--24)的数字.");
}
}
public int getHour()
{
return hour;
}
//封装minute
public void setMinute(int minute)
{
if(minute>=0&&minute<60)
this.minute=minute;
else
{
System.out.println("您设置的时间: "+minute+"非法");
System.out.println("请设置一个[0--60)的数字.");
}
}
public int getMinute()
{
return minute;
}
//封装second
public void setSecond(int second)
{
if(second>=0&&second<60)
this.second=second;
else
{
System.out.println("您设置的时间: "+second+"非法");
System.out.println("请设置一个[0--60)的数字.");
}
}
public int getSecond()
{
return second;
}
//提供私有的获取字符串时间的方法
private String getStrHour()
{
return hour<10?"0"+hour:hour+"";
}
private String getStrMinute()
{
return minute<10?"0"+minute:minute+"";
}
private String getStrSecond()
{
return second<10?"0"+second:second+"";
}
//对外提供显示时间的方法
public void show()
{
System.out.println("当前时间:"+getStrHour()+":"+getStrMinute()+":"+getStrSecond());
}
}
一个典型的面向对象练习题:
编程
ATM 提供的功能 存钱 取钱 查看 exit
程序运行
请输入要执行的操作 1.存 2 取 3查 4 exit
代码如下:
import java.util.*;
class ATMDemo//演示ATM类功能
{
public static void main(String[] args)
{
ATM atm=new ATM("张三","626110",10000.000);
atm.run();
}
}
/**
自己定义的一个ATM类,实现 存钱 取钱 查看 exit 功能
@author 王震阳
@version v1.0
*/
class ATM
{
private double money=0;
private String name;
private String cardID;
ATM(){}
ATM(String name,String cardID,double money)
{
this.name=name;
this.cardID=cardID;
this.money=money;
}
//定义setter and getter
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public void setCardID(String cardID)
{
this.cardID=cardID;
}
public String getCardID()
{
return cardID;
}
public void setMoney(double money)
{
this.money=money;
}
public double getMoney()
{
return money;
}
//存钱方法,存成功以后返回总钱数
public void saveMoney(double money)
{
if(money>0)
{
this.money+=money;
sop("恭喜您已经存入"+money+"元.");
showCount();
}else
{
sop("您要存入的金额非法.");
return;
}
}
//取钱的方法,取成功时返回剩余钱数
public void takeMoney(double money)
{
if(this.money<money)
{
System.out.println("您的余额不足...");
}
else
{
this.money-=money;
showCount();
}
}
//定义一个查看账户的函数
public void showCount()
{
System.out.println("用户信息:\r\n\r\n"+" 姓名: "+this.name+"\r\n"+"当前账户余额: "+this.money+"\r\n");
}
//开始执行程序,模拟ATM工作
public void run()
{
sop("欢迎使用此ATM取款机");
while(true)
{
sop("继续请输入您要办理的业务代码(1/2/3/4):\r\n");
sop("1:存款");
sop("2:取款");
sop("3:查看账户");
sop("4:退出(exit)");
Scanner sc=new Scanner(System.in);
int num=sc.nextInt();
switch(num)
{
case 1:
{
sop("正在处理您的存款业务:");
sop("请输入您要存入的金额");
saveMoney(sc.nextDouble());
break;
}
case 2:
{
sop("正在处理您的取款业务:");
sop("请输入您要取出的金额");
takeMoney(sc.nextDouble());
break;
}
case 3:
{
sop("正在处理您的查看请求...");
showCount();break;
}
case 4:
{
sop("欢迎您再次光临.");
sop("系统正在退出...");
System.exit(0);
}
default:
{
sop("输入不符合要求.");
}
}
}
}
private void sop(Object obj)
{
System.out.println(obj);
}
}
当前账户余额: 8739.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
2
正在处理您的取款业务:
请输入您要取出的金额
455
用户信息:
姓名: 张三
当前账户余额: 8284.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
2
正在处理您的取款业务:
请输入您要取出的金额
8000
用户信息:
姓名: 张三
当前账户余额: 284.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
3
正在处理您的查看请求...
用户信息:
姓名: 张三
当前账户余额: 284.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
2
正在处理您的取款业务:
请输入您要取出的金额
280
用户信息:
姓名: 张三
当前账户余额: 4.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
2
正在处理您的取款业务:
请输入您要取出的金额
4
用户信息:
姓名: 张三
当前账户余额: 0.0
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
2
正在处理您的取款业务:
请输入您要取出的金额
2
您的余额不足...
继续请输入您要办理的业务代码(1/2/3/4):
1:存款
2:取款
3:查看账户
4:退出(exit)
4
欢迎您再次光临.
系统正在退出...
多态:
1.多态的体现
父类的引用指向了自己的子类对象
父类的引用页可以接受自己的子类对象
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现
通常还有一个前提,存在覆盖
3.多态的好处
提高了扩展性,但是只能使用父类的引用访问父类中的成员.
2.复习数组:
补漏:对数组的理解尤其是传值与传址.
数组的传值传址:
堆内存数值的默认值:
二维数组的赋值与遍历:
class ShuZu
{
public static void main(String[] args)
{
int[][] arr2={{1,2,3},{3,4},{10}};
for(int i=0;i<arr2.length;i++)
{
for(int j=0;j<arr2[i].length;j++)
{
System.out.print(arr2[i][j]);
}
System.out.println();
}
}
}
通过函数打印一个二维数组:
class Array2Demo// 二维数组演示
{
public static void main(String[] args)
{
int[] a={7,8,9,10};
int[] b={12,13,14,15,16};
int[][] arr1=new int[][]{{1,2,3},{4,5,6}};
int[][] ab;
int[][] arr2=new int[][]{new int[]{21,32,432,32},new int[]{65,34,21,123},new int[]{2345,123,1234,123,23}};
ab=new int[][]{a,b};
printArray2(arr1);
printArray2(ab);
printArray2(arr2);
}
public static void printArray(int[] arr)
{
for(int i=0;i<arr.length;i++)
{
if(i!=arr.length-1)
System.out.print(arr[i]+", ");
else
System.out.println(arr[i]);
}
}
public static void printArray2(int[][] arr)
{
for(int i=0;i<arr.length;i++)
{
printArray(arr[i]);
}
}
}
---------- java ----------
1, 2, 3
4, 5, 6
7, 8, 9, 10
12, 13, 14, 15, 16
21, 32, 432, 32
65, 34, 21, 123
2345, 123, 1234, 123, 23
Output completed (0 sec consumed) - Normal Termination
class Array2UtilTest//练习二维数组double[][] score = {{87.5, 93.5, 68}, {82.5, 90, 80.5}, {86, 88, 92.5}, {92.5, 58, 73.5}};
{
public static void main(String[] args)
{
double[][] score = {{87.5, 93.5, 68}, {82.5, 20, 80.5}, {16, 88, 92.5}, {92.5, 58, 73.5}};
Array2Util.printBuJiGe(score);
System.out.println(Array2Util.getMax(score));
System.out.println(Array2Util.getMin(score));
System.out.println(Array2Util.getAverage(score));
Array2Util.printEveryAverage(score);
}
}
double[][] score = {{87.5, 93.5, 68}, {82.5, 90, 80.5}, {86, 88, 92.5}, {92.5, 58, 73.5}};
语文 | 数学 | 英语 | |
张三 | 87.5 | 93.5 | 68.0 |
李四 | 82.5 | 90.0 | 80.5 |
王五 | 86.0 | 88.0 | 92.5 |
赵六 | 92.5 | 58.0 | 73.5 |
写一个类对上面二维数据进行必要的操作演示代码如下:
class Array2Util//操作二维数组的工具类
{
//获取最大值的数值,接受一个double型二维数组
public static double getMax(double[][] arr)
{
int maxI=0;//默认脚标为0
int maxJ=0;//
for(int i=0;i<arr.length;i++)
{
for(int j=0;j<arr[i].length;j++)
{
if(arr[maxI][maxJ]<arr[i][j])
{
maxI=i;
maxJ=j;
}
}
}
return arr[maxI][maxJ];//返回最大值
}
//获取最小值
public static double getMin(double[][] arr)
{
int minI=0;//默认脚标为0
int minJ=0;//
for(int i=0;i<arr.length;i++)
{
for(int j=0;j<arr[i].length;j++)
{
if(arr[minI][minJ]>arr[i][j])
{
minI=i;
minJ=j;
}
}
}
return arr[minI][minJ];//返回最小值
}
//获取平均值
public static double getAverage(double[][] arr)
{
double average=0;//初始化平均值为0
int times=1;//初始化循环次数
for(int i=0;i<arr.length;i++)
{
for(int j=0;j<arr[i].length;j++)
{
average+=arr[i][j];
times++;
}
}
return average/times;
}
//打印每个同学的平均分
public static void printEveryAverage(double[][] arr)
{
double tempAverage=0;//定义一个临时的平均值
int tempNum=0;//初始化课目数为1;
for(int i=0;i<arr.length;i++)
{
for(int j=0;j<arr[i].length;j++)
{
tempAverage+=arr[i][j];
tempNum++;
}
sop("个人平均成绩:"+tempAverage/tempNum,true);
tempNum=0;
tempAverage=0;
}
}
//定义一个打印函数,含两个参数,布尔型为真换行,否则为假
private static void sop(Object obj,boolean b)
{
if(b)
{sop(obj+"\r\n");}
else
{System.out.print(obj);}
}
private static void sop(Object obj)
{
System.out.print(obj);
}
//打印不及格的同学的所有成绩
public static void printBuJiGe(double[][] arr)
{
for(int i=0;i<arr.length;i++)
{
if(isFailed(arr[i]))
{
printArray(arr[i]);
sop("\r\n");
}
}
}
//用于判断成绩是否及格,如果不及格返回true,否则返回false
public static boolean isFailed(double[] arr)
{
for(int i=0;i<arr.length;i++)
{
if(arr[i]<60)
return true;
}
return false;
}
public static void printArray(double[] arr)
{
for(int i=0;i<arr.length;i++)
{
sop(arr[i]+" ");
}
}
}
运行结果:
---------- java ----------
82.5 20.0 80.5
16.0 88.0 92.5
92.5 58.0 73.5
93.5
16.0
65.57692307692308
个人平均成绩:83.0
个人平均成绩:61.0
个人平均成绩:65.5
个人平均成绩:74.66666666666667
Output completed (0 sec consumed) - Normal Termination
3.继承与组合
1.1继承
继承是面向对象的三大特性(继承/多态/封装)之一.java的继承是通过extends关键字来实现的,实现继承的类成为子类,被继承的类是父类..java中子类继承父类的语法格式如下:
修饰符 class SubClass extends SuperClass
{
//定义部分
}
需要注意的问题:
1子类无法继承父类的构造器.
4.如果父类的成员变量被private修饰,则子类无法继承
5.如果子类要重写父类的方法,那么子类方法的权限修饰符必须大于等于父类
6.子类方法返回值类型应比父类方法返回值类型更小或相等///为什么没//搞明白,
7.子类方法声明抛出的异常应比父类方法声明抛出的异常类更小或相等
8.覆盖方法要么都是类方法,要么都是实例方法,否则编译错误
9.当子类覆盖了父类方法后,子类的对象将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法.如果在子类方法中调用父类中被覆盖的方法,则可以使用super或者父类名作为调用者来调用父类中被覆盖的方法.
下面用代码示例继承的特点:
class Animal//定义一个父类Animal
{
public int age;
private double weight;
int a=1;
Animal(){}
Animal(int age,double weight)
{
this.age=age;
this.weight=weight;
}
public void eat()
{
System.out.println("animal eat...");
}
}
class Dog extends Animal//定义一个子类狗,继承了父类Animal
{
int a=2;
int dogc=34;
Dog(){}
public void eat()//如果重写了父类的方法,则该方法权限一定要>=父类的权限
{
System.out.println("dog eat...");
}
Dog(int age,double weight)
{
super(age,weight);
}
public void sleep()
{
System.out.println("dog sleep...");
}
}
class extendsDemo//演示继承特点
{
public static void main(String[] args)
{
Dog dog=new Dog();
dog.eat();
//dog.sleep();
System.out.println(dog.a);
System.out.println(dog);
}
}
///如果子类需要调用父类中被覆盖的方法
public void subMethod()
{
//下面语句调用了父类中被覆盖的方法
super.eat();
}
1.2组合
继承是实现类复用的重要手段,组合也是实现类重用的重要方式,对于继承而言,子类可以直接获得父类的public方法,程序使用子类时,将可以直接访问该子类从父类那里继承到的方法,而组合则是把旧类对象作为新的Field嵌入,用以实现新类的功能,用户看到的新类的方法,而不能看到被嵌入对象的方法,因此,通常需要在新类里使用private修饰被嵌入的旧类对象.
一个简单的组合代码:
class ZuHeDemo// 演示组合的应用
{
public static void main(String[] args)
{
Animal ani=new Animal();
Dog dog=new Dog(ani);
dog.eat();
}
}
class Animal//定义一个Animal类
{
public String str="Animal";
public void eat()
{
System.out.println("Anmal eat...");
}
}
class Dog
{
private Animal ani;
Dog(Animal ani)
{
this.ani=ani;
}
public void eat()
{
ani.eat();
}
}
4.初始化代码块
java的初始化代码块与构造器的作用比较形似,它的主要作用是对java对象进行初始化操作.初始化块的修饰符只能是static,使用static的初始化块被称为静态初始化块.初始化代码块里的代码可以包含任何可执行性语句,包括定义局部变量,调用其他对象的方法,以及使用分支/循环语句等.
4.1普通代码块
当创建java对象时,系统总是先调用该类里定义的初始化块,,而且在执行构造器之前执行.下面以一段简单的代码演示:
class Demo//代码块演示
{
Demo()
{
System.out.println("构造函数开始运行...");
}
{
System.out.println("代码块开始运行....");
int a=6;
if(a>3)
{
System.out.println("a的值大于3");
}
else
{
System.out.println("a的值小于3");
}
}
public static void main(String[] args)
{
Demo d=new Demo();
}
}
---------- java ----------
代码块开始运行....
a的值大于3
构造函数开始运行...
输出完毕 (耗时 0 秒) - 正常终止
当java创建一个对象时,系统先为该对象的所有实例Field分配内存,接着程序开始对这些实例变量执行初始化,其初始化顺序是:先执行初始化块或声明Field时指定的初始值,再执行构造器里指定的初始值.下面代码演示了该过程:
class ChuShiDemo//演示程序初始化顺序
{
ChuShiDemo()
{
System.out.println("构造函数运行....");
}
{
System.out.println("代码块运行...");
x=2;
//System.out.println("x的值为:"+x);这时打印x的值编译无法通过.
}
int x=10;
public static void main(String[] args)
{
ChuShiDemo cs=new ChuShiDemo();
}
}
---------- java ----------
代码块运行...
构造函数运行....
输出完毕 (耗时 0 秒) - 正常终止
4.2静态代码块
静态初始化块也成为类初始化块.系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行.因此静态初始化块比普通初始化块先执行.静态初始化块属于类的静态成员,同样遵循静态成员不能访问非静态成员的规则,因此静态初始化块不能访问非静态成员,包括不能访问实例Field和实例方法.
4.3Person p=new Person(“张三”,25);这句话都做了些什么?
1.因为new用到了Person.class,所以会先将Person.class文件加载到内存中
2.执行该类中static代码块,如果有的话,给Person进行初始化
3.在堆内存中开辟空间,分配内存地址
4.在堆内存中建立对象的特有属性,并进行默认初始化
5.对属性进行显示初始化
6.对对象进行构造代码块初始化
7.对对象进行构造函数初始化
8.将内存地址赋给栈内存的p变量
5.帮助文档的制作
帮助文档就好比程序的说明书.java的说明书通过注释来完成.
下面的程序代码演示了一个打印数组操作类的注释.
/**
该类可以实现对数组的打印操作
@author 王震阳
@version 1.001
*/
public class ArrayTool
{
/**
该方法可以对整型数组进行打印
@param arr 整型数组
*/
public static void printArr(int[] arr)
{
System.out.print("[");
for(int i=0;i<arr.length;i++)
{
if(i!=arr.length-1)
{
System.out.print(arr[i]+",");
}
else
{
System.out.print(arr[i]+"]");
}
}
System.out.println();
}
/**
该方法可以对浮点型数组进行打印操作
@param arr double型数组
*/
public static void printArr(double[] arr)
{
System.out.print("[");
for(int i=0;i<arr.length;i++)
{
if(i!=arr.length-1)
{
System.out.print(arr[i]+",");
}
else
{
System.out.print(arr[i]+"]");
}
}
System.out.println();
}
}
6.单例设计模式/模板方法模式
6.1单列设计模式
class SingleDemo //单例设计模式
{
public static void main(String[] args)
{
Single_1 sin1=Single_1.getInstance();
sin1.sop_1("test");
Single_2 sin2=Single_2.getInstance();
sin2.sop_2("test2");
}
}
class Single_1//懒汉式
{
private Single_1(){}//将构造函数私有化,禁止new该对象
private static Single_1 sin1=new Single_1();
public static Single_1 getInstance()
{
if(sin1!=null)
return sin1;
return null;
}
public void sop_1(Object obj)
{
System.out.println("懒汉式 "+obj);
}
}
class Single_2//饿汉式
{
private Single_2(){}//将构造函数私有化,禁止new对象
private static Single_2 sin2=null;
public static Single_2 getInstance()
{
if(sin2==null)
return new Single_2();
return null;
}
public void sop_2(Object obj)
{
System.out.println("饿汉式 "+obj);
}
}
6.2模版方法模式
7.多态
java引用变量有两个类型,一个是编译时类型,一个是运行时类型.编译时类型由声明该变量时使用的类型确定,运行时类型,由实际赋给该变量的对象决定.如果编译时类型和 运行时类型不一致,就可能出现多态.也就是说相同类型的变量调用同一个方法时,呈现出来的不同的行为特征.比如狗和猫都属于动物类.猫调用动物类的叫声和狗调用动物类的叫声是不一样的.这就是多态.(polymorphic)
多态演示代码如下:
class PolymorphicDemo//演示多态
{
public static void main(String[] args)
{
Animal an=new Animal();//编译时类型和运行时类型一致,不存在多态现象
System.out.println(an.str);
an.sleep();
an.eat();
Dog dog=new Dog();//编译时类型和运行时类型一致,不存在多态现象
System.out.println(dog.str);
dog.sleep();
dog.eat();
dog.kanjia();
Animal an2=new Dog();//编译时类型和运行时类型不一致,存在多态现象
System.out.println(an2.str);
an2.sleep();
an2.eat();
//编译时报错,因为Animal没有kanjia()方法
//an2.kanjia();
}
}
class Animal //定义一个动物类
{
public String str="这是Animal类";
public void eat()
{
System.out.println("Animal eat...");
}
public void sleep()
{
System.out.println("Animal sleep...");
}
}
class Dog extends Animal//定义一个Dog类继承Animal类
{
public String str="这是Dog类";
public void eat()//覆写父类的eat方法
{
System.out.println("Dog eat...");
}
public void kanjia()//Dog类特有的方法
{
System.out.println("Dog kan jia....");
}
}
运行结果:
---------- java ----------
这是Animal类
Animal sleep...
Animal eat...
这是Dog类
Animal sleep...
Dog eat...
Dog kan jia....
这是Animal类
Animal sleep...
Dog eat...
Output completed (0 sec consumed) - Normal Termination
多态的规律:
对于成员变量:编译时和运行时都看左边
对于成员函数:编译时看左边,运行时看右边.
8.抽象类
当多个类中出现多个相同功能,但是功能主体不同,这时可以向上抽取.
抽象类的特点:
1.抽象方法一定在抽象类中
2.抽象方法和抽象类都必须被abstract修饰
3.抽象类不可以new对象,因为调用抽象方法没有意义.
4.抽象类中的方法还要被使用,必须由子类复写所有抽象方法,如果子类只复写了部分抽象方法,那么该类还属于抽象类.
5.抽象的好处是可以强制子类实现其抽象方法.
6.抽象类里可以没有抽象方法,其作用就是不让该类new 对象
下面代码演示了抽象的 基本使用方法:
abstract class Employee//一个员工的抽象类
{
private String name;
private String ID;
private double pay;
Employee(String name,String ID,double pay)
{
this.name=name;
this.ID=ID;
this.pay=pay;
}
abstract void work();//定义一个抽象方法
}
class AbstractDemo//演示抽象类
{
public static void main(String[] args)
{
Manager ma=new Manager("张三","1110",2000,3000);
ma.work();
}
}
class Manager extends Employee//Manager类继承了Employee类
{
private double salary;
Manager(String name,String ID,double pay,double salary)
{
super(name,ID,pay);
this.salary=salary;
}
public void work()//覆写父类的work()方法
{
System.out.println("manager work");
}
}
---------- java ----------
manager work
输出完毕 (耗时 0 秒) - 正常终止
9.接口
9.1接口基本概念
接口是从多个相似类中抽象出来的规范,接口不提供任何实现,接口体现的是规范和实现分离的设计哲学.让规范和实现分离的好处是接口的好处,让软件系统的各个组件之间面向接口耦合.这样可以为软件提供更好的可拓展性和可维护性.
和类不同接口不再使用class关键字,而是使用interface关键字.接口定义的基本语法如下:
public interface 接口名 extends 父接口1,父接口2...
{
public static final 常量定义;
public abstract 方法();
}
接口的修饰符可以是public 也可以不写,如果不写则默认采用包权限访问控制符.,即只有在相同包结构下才可以使用此接口.
一个接口可以有多个直接父接口,但是接口只能继承接口不能继承类
对于接口里的常量Field而言,他们只能是常量,因此系统会自动为这些Field增加static final修饰符,也就是在定义Field是不管是否使用public static final 修饰符,接口里的Field总将使用者三个修饰符来修饰.
接口里没有构造器和初始化块,因此接口里定义的Field只能在定义时指定默认值
接口里的方法只能是抽象,因此系统会自动增加abstract修饰符
接口里不允许定义静态方法,,
接口里定义的内部类,接口.枚举类默认都采用public static 关键.
实现接口方法时,必须使用public访问控制符,因为interface里的方法都是public的,子类复写时权限只能大于等于父类权限.
class InterfaceDemo implements JieKou//演示接口的使用
{
public void show(Object obj)//覆写接口中的方法
{
System.out.println(obj);
}
public static void main(String[] args)
{
JieKou jk=new InterfaceDemo();//这里其实体现了一种面向接口的编程思想
jk.show(STR);
}
}
interface JieKou
{
public static final String STR="interface 字符串常量";
public abstract void show(Object obj);
}
9.2利用接口实现工厂模式
设计模式就是对经常出现的软件设计问题的成熟解决方案,实际上设计模式仅仅是对特定问题的一种惯性思维.
下面代码实现了这样的情景:一台电脑,需要输入文字,然后屏幕显示文字.键盘负责接收输入的内容,屏幕负责输出内容.电脑要提供键盘接口和屏幕接口.分析:
建立两个接口一个是键盘接口一个是屏幕接口,建立两个类分别实现键盘接口和屏幕接口.
interface KeyIn//键盘接口
{
public abstract String getData(String str);
}
interface ScreenOut//屏幕接口
{
public abstract void showData(String str);
}
class KeyBoard implements KeyIn//键盘类实现了键盘接口
{
public String getData(String str)
{
return "使用键盘输入的数据: "+str;
}
}
class Screen implements ScreenOut//屏幕类实现了屏幕输出接口
{
public void showData(String str)
{
System.out.println("屏幕输出的内容为: "+str);
}
}
class Computer//定义一个电脑类,里面包含了键盘和屏幕两个接口
{
private KeyIn ki;
private ScreenOut so;
public Computer(KeyIn ki,ScreenOut so)
{
this.ki=ki;
this.so=so;
}
public void run()//定义一个电脑运行方法
{
String str=ki.getData("这是从键盘输入的数据.");
so.showData(str);
}
}
class ComputerDemo//主函数放在该类里,演示工厂类
{
public static void main(String[] args)
{
Computer com=new Computer(new KeyBoard(),new Screen());
com.run();
}
}
---------- java ----------
屏幕输出的内容为: 使用键盘输入的数据: 这是从键盘输入的数据.
输出完毕 (耗时 0 秒) - 正常终止
10.内部类
定义在一个类中的类成为内部类,内部类的作用如下
1.内部类提供了更好的封装,可以把内部类隐藏在外部类之内,这样就不允许同一个包中的其他类访问该类.
2.内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问.但是外部类不能访问内部类的实现细节.
3.匿名内部类适合用于创建那些仅需要一次使用的类.
10.1内部类访问规则
内部类概述
在一个类的内部再定义一个类。
这就形成了外部类和内部类!
class A {
class B {
class C {}
}
}
class A {
}
class B {
private A a;
public B(A a) {
this.a = a;
}
}
1 什么是内部类
把一个类定义在另一个类的内部,那么这个类就是内部类了。
2 成员内部类
所有称呼为成员的东西都是被类体直接包含的东西。
3 一般内部类都是私有的
一般一个内部类都是私有的!
也就是说,内部类只能被外部类使用。
4 内部类访问外部类成员
内部类中可以直接访问外部类成员,包含私有成员。
5 外部类中使用创建内部类对象
外部类中使用内部类,需要创建对象。
也就是说,外部类对内部类没有什么特权,就和使用其他类一样!
如果内部类是private,那么这个内部类只能被外部使用。这也算是外部类的一点特权吧!
6 内部类拥有外部类对象(与继承相似)
每个内部类对象,都有一个外部类对象。
所以内部类对象,无需去创建外部类对象,就可以直接访问外部的成员!
7 内部类的class文件
成员内部类 class文件:外部类名$内部类名.class
9 非static内部类不能拥有static的属性和方法
正常类:不能使用static来修饰
内部类:可以使用static来修饰。
非静态内部类,不能拥有static的所有东西!
考点!
class A {
class B {
public static void fun() {}
}
}
局部内部类(很少用)
把语法了解了,也就可以了。
1 方法内部的类是局部内部类
class A {
public void fun() {
class B {}//局部内部类
}
}
2 局部内部类还可以访问所在的局部中所有局部变量
例如一个B类,定义在A类的fun()方法中,那么B类就可以使用A类fun()方法中的局部变量(包含fun()方法形参)。
但要求局部变量(或形参),必须是final的。
3 局部内部类不能使用访问修饰符和静态修饰符
局部内部类不能使用修饰符!
4 局部内部类只在局部可见
局部内部类不能使用private等访问修饰符、也不能使用static。
局部内部类与成员内部类是一样的!(不能有static成员,可以直接访问外部类的所有成员)
局部内部类可以访问局部的final变量(包含形参)
5 局部内部类的class文件
外部类的名字$编号内部类名字
6 多次调用局部方法,只会创建一个局部内部类
类在编译时已经生成了.class文件,在运行时已经没有内部类一说。
7 局部内部类不能拥有静态的属性和方法
局部内部类不能拥有静态属性和静态方法。
这一点和成员内部类相同!
局部匿名内部类
局部匿名内部类:又叫匿名类!
匿名类不能有构造器
1 匿名内部类的语法
把一个类的定义放到new语句中去了。
一个东西没名字,就表示它只能被使用一次!
一个类要是没有名字,那么这个类只能被使用一次!
问一下自己:定义一个类什么目的?为了创建这个类的对象!
也就是说,因为一个匿名类只能被使用一次,那么我们就需要在这时创建它的对象!
所以匿名内部类必须放到new语句中使用。
new 接口或父类名() {类体}
new A(); à new A() {};
new A():创建A类的对象。
A a = new A() {}:创建A类的子类对象,而这个子类也是刚刚创建的。这个子类没有名字!虽然不知道这个子类叫什么名字,但可以使用A类的引用来指向它!
也就是说,我们只能使用他父类的引用来指向它,那么这个引用也就只能调用A类中存在的方法,而不能再去调用子类独有的方法。
这说明,匿名内部中,都是在重写父类方法,如果写独有方法,也没能被调用,那么你写它干什么。
2 匿名内部类只能使用一次
只能被使用一次,对类的使用也就一种方式,创建这个类的对象!
3 匿名内部类必须指定父类或者指定实现的接口
new 父类或接口(){}
必须指定父类或者实现的接口。
匿名内部类与正常类不一样,它只能指定一个要继承的类或者是指定一个要实现的接口。两者不能兼得!
实现接口,也只能实现1个。要实现接口,就不能指定父类!
4 匿名内部类不能同时继承和实现
匿名内部类与正常类不一样,它只能指定一个要继承的类或者是指定一个要实现的接口。两者不能兼得!
实现接口,也只能实现1个。要实现接口,就不能指定父类!
5 匿名内部类最多实现一个接口
实现接口,也只能实现1个。要实现接口,就不能指定父类!
6 匿名内部类的实例块(乐一下)
new A() {
{//构造代码块}//代替了构造器的工作
}
嵌套类
通常嵌套类都是public的。60%是public!
1 什么是嵌套类
给成员内部类使用static修饰一下就是嵌套类了,所以它也叫静态内部类。
2 嵌套类中不能访问外部类的实例东东
可以这么来理解:静态方法中都不能访问本类的实例属性和实例方法。那么静态内部类中也同样不能访问外部类的实例属性和实例方法。
3 嵌套类基本与外部类没什么关系
通常我们定义一个内部类,有两个好处:
l 可以直接使用内部类的成员!但静态内部类就没有这个好处了。
l 隐藏代码,所以嵌套类的好处就是隐藏代码!
4 接口中可以定义嵌套类
public interface A {
class B {}//默认是public static的。
interface C {}
}
API中存在!
通常它们总是在接口中再定义一个接口。
5 嵌套类一般是public的
也就是说,外界会知道嵌套类的存在!
6 外界使用嵌套类
外部类名.内部类名 a = new 外部类名.内部类名();
内部类的好处
1 隐藏代码
隐藏代码!
interface A {}
public class B {
public A fun() {
retrun new Haha();
}
private class AImpl implements A {}
private class Haha implements A {}
}
B b = new B();
A a = b.fun();
//可以使用a,但外界不知道A是哪个具体的类型,这说明将来我们可以修改B类的fun()方法,使用另一个A类的实现,外界也不知道。
2 隐藏实现
l 外部类提供返回某一接口的实现对象
3 内部类可以使用外部类的成员
内部类可以使用外部类成员,但静态内部类不能使用外部类的非静态成员!
内部类总结
1 内部类是编译期状态
也就是说,JVM和昨天的你一样,不知道什么内部类!
就是编译器知道!
也就是说编译器要把内部类变成正常类,不然JVM看不懂!
内部类破坏了封装性!
2 最常见的内部类使用
局部内部类:
l 调用参数类型为接口的方法时;public void fun(A a),其中A是接口类型
fun(new A() {});
l 在返回值类型为接口类型的方法中;
A fun() {
return new A() {};
}
成员内部类:
l 内部类需要使用外部类的成员;
l 内部类只在外部类中使用;
嵌套类:
l 在抽象类或接口中定义自己的子类或实现类;
l 一般不是在外部类内部使用,而是在外界使用;
内部类可以直接访问外部变量,但是外部方法不可以直接访问内部变量,如果要访问那么必须先创建一个内部对象,然胡用该对象访问内部变量.
内部类访问规则代码示例如下:
/**
该代码用于演示内部类的使用方法
@author 王震阳
@version 1.0
*/
public class InnerDemo
{
public static void main(String[] args)
{
Outer.Inner in=new Outer().new Inner();
in.sop1();//运算结果 sop1: a= 3
in.sop2();//运算结果 sop2 this.a= 2
in.sop3();//运算结果 sop3 new Outer().a= 1
in.sop4();//运算结果 sop4 Outer.this.a= 1
in.sop5();//运算结果 sop5 Inner.this.a= 2
in.sop6();//运算结果 sop6 new Inner().a= 2
}
}
class Outer
{
int a=1;
class Inner
{
int a=2;
public void sop1()
{
int a=3;
System.out.println("sop1: a= "+a);//程序查找变量a的顺序是先从自己方法中的局部变量开始的
}
public void sop2()
{
int a=3;
System.out.println("sop2 this.a= "+this.a);//程序通过this可以调用本类的成员变量a
}
public void sop3()
{
int a=3;
System.out.println("sop3 new Outer().a= "+ new Outer().a);//这里其实是新建了一个外部类.,然后调用该外部类的成员变量a,因此结果是1
}
public void sop4()
{
int a=3;
System.out.println("sop4 Outer.this.a= "+ Outer.this.a);//调用外部类Outer的this方法可以调用外部类的成员变量a,因此结果为1
}
public void sop5()
{
int a=3;
System.out.println("sop5 Inner.this.a= "+ Inner.this.a);//调用内部类的this方法获取该内部类的成员变量.,因此结果为2
}
public void sop6()
{
int a=3;
System.out.println("sop6 new Inner().a= "+ new Inner().a);//创建一个内部类,并调用该类的成员的变量a,因此结果为2
}
}
}
运行结果:
---------- java ----------
sop1: a= 3
sop2 this.a= 2
sop3 new Outer().a= 1
sop4 Outer.this.a= 1
sop5 Inner.this.a= 2
sop6 new Inner().a= 2
输出完毕 (耗时 0 秒) - 正常终止
10.2匿名内部类
匿名内部类个格式:
new 父类构造器(实参列表)|实现接口
{
//匿名内部类的类体部分
}
匿名内部类必须继承一个父类,或者实现一个接口,但是最多只能继承一个父类或者继承一个接口(这里不知道为什么?类是可以实现多个接口的,但是匿名内部类却不可以)
匿名内部类不能是一个抽象类,因为在创建匿名内部类时,会立即创建该类的对象.
匿名内部类不能定义构造器,
匿名内部类可以定义实例初始化块
如果匿名内部类需要访问外部类的局部变量,则必须使用final 修饰符来修饰外部类的局部变量.//具体原因是由程序的加载循序决定的?
下面代码演示了一个匿名内部类,该类实现了一个接口.
class AnonymousDemo//演示一个简单的匿名内部类
{
public static void main(String[] args)
{
new A()
{
public void sop(Object obj)
{
System.out.println(obj);
}
}.sop("测试匿名内部类");
}
}
interface A//定义一个接口A
{
public abstract void sop(Object obj);//定义一个抽象方法
}
---------- java ----------
测试匿名内部类
输出完毕 (耗时 0 秒) - 正常终止
10.3静态内部类
如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类某个对象.静态内部类可以包含静态成员,也可以包含非静态成员,根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员.即使是静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员.
外部类不能直接访问静态内部了的成员,但是可以使用静态内部类的类名作为调用者来访问静态内部类的静态成员(类成员),也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员.
下面代码演示:
class OuterClass//演示静态内部类的访问规则
{
public static void main(String[] args)
{
System.out.println("InnerClass.a= "+InnerClass.a);//可以通过内部类的类名访问内部类的静态变量a
System.out.println("new InnerClass().b= "+new InnerClass().b);//可以通过内部类对象访问内部类的实例变量
}
static class InnerClass//定义一个静态内部类
{
public static int a=1;
public int b=2;
}
}
---------- java ----------
InnerClass.a= 1
new InnerClass().b= 2
输出完毕 (耗时 0 秒) - 正常终止
11.异常处理
11.1.异常基础与总结
/**
自定义异常类,该类实现了一个简单的除法,该除法不允许为负数,如果为负数则抛出异常
@author 王震阳
@version v1.0
*/
class ExceptionDemo //演示异常类
{
public static void main(String[] args)
{
try
{
System.out.println(div(10,2));
System.out.println(div(10,-2));
}
catch (MyException mye)
{
System.out.println(mye.toString());
}
}
public static int div(int a,int b) throws MyException
{
if(b<=0)
{
throw new MyException("小于等于0的数不能当做除数:",b);
}
return a/b;
}
}
/**
自定义异常类,继承了异常类
*/
class MyException extends Exception
{
public int num;
public String msg;
MyException()
{
super();
}
MyException(String msg,int num)
{
this.msg=msg;
this.num=num;
}
public String toString()
{
return msg+num;
}
}]
异常类总结:
异常体系:
ThrowAble
|---Error
|--Exception
|--RuntimeException
|---其他普通异常
异常体系的特点:
异常类中所有建立的类已经对象都具有可抛性
也就是说可以被throws和throw关键字所操作
只有异常体系具有这个特点.
throw 和throws用法的区别
throw用在方法内,只能抛异常对象
throws用在方法上,只能抛异常类,可以抛多个异常类,用逗号隔开
当函数有throw抛出异常时,并未进行内部的try处理,那么必须在方法上声明,否则编译失败,但是该规则不适用于RuntimeException.也就是说如果函数内抛出了一个RuntimeException对象,那么可以不在函数上声明异常类.
如果函数声明了抛出异常,调用者需要进行处理,处理方式可以是try,也可以是throws.
异常有两种.:
编译时被检测异常:如果没有处理(没有抛也没有try),编译失败,该异常被标识,代表可以被处理.
运行时异常(编译时不检测):在编译时不需要处理,编译器不检查
该异常的出现不需要进行处理,让程序自动停止,需要改动代码
异常的好处:
1.将问题封装成对象
2.将正常流程代码和异常分来处理,便于阅读
异常处理原则:
1.异常处理方式有两种:try或throws
2.调用到抛出的异常的功能时,抛出几个就处理几个,不多不少.
3.多个catch时,父类的catch放在最下面
4.catch内需要定义针对性的处理方式.不要简单的定义printStackTrace语句
当捕获到的异常.本功能处理不了时,可以继续在catch中抛出,也就是在catch中继续抛出.
异常的注意事项:
在子父类覆盖时,子类抛出的异常必须是父类异常的子类或子集.如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛
11.2毕向东老师异常练习整理:
1.写出程序结果:
class Demo
{
public static void func()
{
try
{
throw new Exception();
}
finally
{
System.out.println("B");
}
}
public static void main(String[] args)
{
try
{
func();
System.out.println("A");
}
catch (Exception e)
{
System.out.println("c");
}
System.out.println("D");
}
}
运行结果:编译失败.因为上面try里面抛出了一个非运行时异常,但是没有catch进行处理.如果想编译通过,可以加上catch方法:
class Demo
{
public static void func()
{
try
{
throw new Exception();
}
catch(Exception e)
{
System.out.println("f");
}
finally
{
System.out.println("B");
}
}
public static void main(String[] args)
{
try
{
func();
System.out.println("A");
}
catch (Exception e)
{
System.out.println("c");
}
System.out.println("D");
}
}
运行结果:
---------- java ----------
f
B
A
D
Output completed (0 sec consumed) - Normal Termination
该题也可以在func()函数上加上抛出异常类声明处理:
class Demo
{
public static void func() throws Exception
{
try
{
throw new Exception();
}
finally
{
System.out.println("B");
}
}
public static void main(String[] args)
{
try
{
func();
System.out.println("A");
}
catch (Exception e)
{
System.out.println("c");
}
System.out.println("D");
}
}
运行结果如下:
---------- java ----------
B
c
D
Output completed (0 sec consumed) - Normal Termination
2.写成程序运行结果
class Demo2 extends Test
{
Demo2()
{
super();
System.out.println("Demo2");
}
public static void main(String[] args)
{
new Demo2();
new Test();
}
}
class Test
{
Test()
{
System.out.println("Test");
}
}
---------- java ----------
Test
Demo2
Test
Output completed (0 sec consumed) - Normal Termination
3,写出运算结果//考察子类继承实现父类时,方法的调用知识
class Demo3
{
public static void main(String[] args)
{
A a=new B();
System.out.println(a.func());
}
}
interface A
{
}
class B implements A
{
public String func()
{
return "func";
}
}
---------- javac ----------
Demo3.java:6: 错误: 找不到符号
System.out.println(a.func());
^
符号: 方法 func()
位置: 类型为A的变量 a
1 个错误
Output completed (0 sec consumed) - Normal Termination
4.写成运算结果
class Demo4 extends Fu
{
public static void main(String[] args)
{
int i=0;
Fu f=new Demo4();
Demo4 d=new Demo4();
for(f.show('A');f.show('B')&&(i<2);f.show('C'))
{
i++;
d.show('D');
}
System.out.println("Hello World!");
}
boolean show(char a)
{
System.out.println(a);
return false;
}
}
class Fu
{
boolean show(char a)
{
System.out.println(a);
return true;
}
}
运行结果:A B(另起一行)
5.写出预算结果
class Demo5
{
static A get()
{
return new B();
}
public static void main(String[] args)
{
A a=get();
System.out.println(a.test);
}
}
interface A{}
class B implements A
{
public String test()
{
return "yes";
}
}
运行结果:编译失败,因为编译时看A没有test()方法.
6.写出运算结果
class Demo6 extends Super
{
public Demo6(String a)
{
System.out.println('C');
i=5;
}
public static void main(String[] args)
{
int i=4;
Super D=new Demo6("A");
System.out.println(D.i);
}
}
class Super
{
int i=0;
public Super(String a)
{
System.out.println('A');
i=1;
}
public Super()
{
System.out.println('B');
i+=2;
}
}
运行结果:B C 5
7.补足代码//考察匿名内部类
class Demo7
{
public static void main(String[] args)
{
//补足代码;调用两个函数要求用匿名内部类
new Inter(){
public void show(int a,int b)
{
System.out.println(a+"+"+b+"="+(a+b));
}
public void func()
{
System.out.println("覆写func,匿名内部类");
}
}.show(1,2);
new Inter(){
public void show(int a,int b)
{
System.out.println(a+"+"+"b"+"="+a+b);
}
public void func()
{
System.out.println("覆写func,匿名内部类");
}
}.func();
}
}
interface Inter
{
void show(int a,int b);
void func();
}
8.写出运算结果//考察内部类
class Demo8
{
public static void main(String[] args)
{
TD.Inner ti=new TD().new Inner();
ti.show();
}
}
class TD
{
int y=6;
class Inner
{
static int y=3;
void show()
{
System.out.println(y);
}
}
}
//编译失败:非静态内部类中不可以定义静态成员,内部类如果定义了静态成员,该内部类必须被静态修饰.
9.选择题,写出错误答案的原因
class Demo
{
int show(int a,int b){return 0;}
}
A.public int show(int a,int b){return 0;}//复写父类,这个可以
B.private int show(int a,int b){return 0;}//权限比父类低不可以
C.private int show(int a,long b){return 0;}//属于函数重载可以
D.public short show(int a,int b){return 0;}//不可以
E.static int show(int a,int b){return 0;}//不可以,静态只能覆盖静态方法
10.this关键字的特点和final的含义
this:代表本类对象,哪个对象调用this所在的函数,this就代表哪个对象
final:
1.修饰类,变量(成员变量,静态变量,局部变量),函数
2.修饰的类不可以被继承
3.修饰的函数不可以被覆盖
4.修饰的变量不可以被再赋值
5.内部类只能访问外部类中final修饰的变量
11.写出运算结果
class Demo11
{
public static void main(String[] args)
{
Fu f=new Zi();
Zi z=new Zi();
System.out.println(f.num);//4
System.out.println(z.num);//5
z.show();//showZi
f.show();/?showZi
}
}
class Fu
{
int num=4;
void show()
{
System.out.println("showFu");
}
}
class Zi extends Fu
{
int num=5;
void show()
{
System.out.println("showZi");
}
}
12.补全代码
class D
{
public static void main(String[] args)
{
C c=new C();
c.add(4,2);
c.show();//通过该函数打印以上两个数的和
}
}
interface A
{
void show();
}
interface B
{
void add(int a,int b);
}
class C implements A,B
{
//程序代码
int c;
public void add(int a,int b)
{
this.c=a+b;
}
public void show()
{
System.out.println(c);
}
}
13.写成运行结果//考察异常的捕获知识
class Demo13
{
public static void main(String[] args)
{
try
{
showExce();
System.out.println("A");
}
catch (Exception e)
{
System.out.println("B");
}
finally
{
System.out.println("C");
}
System.out.println("D");
}
public static void showExce() throws Exception
{
throw new Exception();
}
}
运行结果:BCD
14.写出程序结果//考察函数的构造
class Demo14 extends Super
{
public Demo14(String s)
{
i=2;
}
public static void main(String[] args)
{
Demo14 d=new Demo14("yes");
System.out.println(d.i);
}
}
class Super
{
int i=0;
Super(){}
public Super(String s)
{
i=1;
}
}
运行结果:2
如果去掉父类中的无参构造器则编译失败,或者子类通过super()调用子类要使用的父类中的构造函数.
将上题代码修改以后可以看到构造器的运行顺序:
class Demo14 extends Super
{
public Demo14()
{
System.out.println("Demo14的无参构造器");
}
public Demo14(String s)
{
System.out.println("Demo14的有参构造器");
i=2;
}
public static void main(String[] args)
{
Demo14 d=new Demo14("yes");
System.out.println(d.i);
}
}
class Super
{
int i=0;
Super()
{
System.out.println(i+"无参构造器");
}
public Super(String s)
{
i=1;
System.out.println(i);
}
}
运行结果如下:
---------- java ----------
0无参构造器
Demo14的有参构造器
2
Output completed (0 sec consumed) - Normal Termination
15.写出程序结果//考察函数重载与复写父类方法
class Demo15 extends Super
{
public long get(){return 5;}
public static void main(String[] args)
{
Super s=new Demo15();
System.out.println(s.get());
}
}
class Super
{
public int get(){return 4;}
}
运行结果:编译失败
16.写出程序结果
class Demo16
{
public static void main(String[] args)
{
try
{
func();
}
catch (Exception e)
{
System.out.println("c");
}
System.out.println("D");
}
public static void func()
{
try
{
throw new Exception();
System.out.println("A");
}
catch (Exception e)
{
System.out.println("B");
}
}
}
编译失败:
---------- javac ----------
Demo16.java:20: 错误: 无法访问的语句
System.out.println("A");
^
1 个错误
Output completed (0 sec consumed) - Normal Termination
17.补全代码//考察内部类的访问规则
class Demo17
{
public void func()
{
//位置1
new Inner();//可以
}
class Inner{}
public static void main(String[] args)
{
Demo17 d=new Demo17();
//位置2
//new Inner();//不可以,因为主函数是静态的,只能访问静态成员
new Demo17().new Inner();
d.new Inner();
}
}
//A.在位置1写new Inner();
//B.在位置2写new Inner();
//C.在位置2写new d.Inner();
//D.在位置2写new Demo17.Inner();,因为Innerclass不是静态的,不属于类
18.写出结果//考察异常捕获的顺序
class Exc0 extends Exception{}
class Exc1 extends Exc0{}
class Demo18
{
public static void main(String[] args)
{
try
{
throw new Exc1();
}
catch (Exception e)
{
System.out.println("Exception");
}
catch(Exc0 e)
{
System.out.println("Exc0");
}
}
}
运行结果:编译失败
19.补全代码//考察匿名内部类
class Demo19
{
public static void main(String[] args)
{
//补足代码:要求用匿名内部类
new Demo19().show(new Test(){
public void func()
{
System.out.println("haha");
}
});
}
void show(Test t)
{
t.func();
}
}
interface Test
{
void func();
}
20.写出程序结果//考察异常和finally
class Demo20
{
public static String output="";
public static void foo(int i)
{
try
{
if(i==1)
throw new Exception();
output+="1";
}
catch (Exception e)
{
output+="2";
return;
}
finally
{
output+="3";
}
output+="4";
}
public static void main(String[] args)
{
foo(0);
System.out.println(output);//134
foo(1);
System.out.println(output);//13423
}
}
21.建立一个图形接口,声明一个面积函数,图形和面积都实现这个接口,并得出两个图形的面积.注:体现面向对象的特征,对数值进行判断,用异常处理,不合法的数值要进行”该数字非法提示”,不再进行运算.
class Demo21//建立一个图形接口,声明一个面积函数,图形和面积都实现这个接口
{
public static void main(String[] args)
{
try
{
Graph juxing=new JuXing(3,4);
Graph circle=new Circle(-1);
System.out.println(juxing.area());
System.out.println(circle.area());
}
catch (MyException e)
{
System.out.println(e.toString());
}
}
}
interface Graph
{
double area();
}
class JuXing implements Graph
{
private double length;
private double height;
public double area()
{
return length*height;
}
JuXing(double length,double height) throws MyException
{
if(length<0||height<0)
throw new MyException("输入的字非法:");
this.length=length;
this.height=height;
}
}
class Circle implements Graph
{
public static final double PI=3.14;
private double radius;
public double area()
{
return PI*(radius*radius);
}
Circle(double radius) throws MyException
{
if(radius<0)
throw new MyException("构造circle时,输入的数字非法");
this.radius=radius;
}
}
class MyException extends Exception
{
private String msg;
private double num;
MyException(){}
MyException(String msg,double num)
{
super(msg);
this.num=num;
}
MyException(String msg)
{
super(msg);
}
}
22.补足compare函数的代码,不允许添加函数.
class Demo22
{
public static void main(String[] args)
{
Circle cir[]=new Circle[3];//创建一个类类型数组
cir[0]=new Circle(1.0);
cir[1]=new Circle(2.0);
cir[2]=new Circle(4.0);
System.out.println("最大的半径值是:"+Circle.compare(cir));
}
}
class Circle
{
private static double pi=3.14;
private double radius;
public Circle(double r)
{
radius=r;
}
public static double compare(Circle[] cir)
{
//程序代码,其实就是在求数组中的最大值.
double max=cir[0].radius;
for(int i=0;i<cir.length;i++)
{
if(max<cir[i].radius)
max=cir[i].radius;
}
return max;
}
}
23.写出运行结果//考察|与||
class Demo23
{
private static int j=0;
private static boolean methodB(int k)
{
j+=k;
return true;
}
public static void methodA(int i)
{
boolean b;
b=i<10|methodB(4);
b=i<10||methodB(8);
}
public static void main(String[] args)
{
methodA(0);
System.out.println(j);
}
}
结果为4.
24.假如我们在开发一个系统时需要对员工进行建模,员,工包含3个属性:姓名/工号/工资.经理也是员工,除了含有员工的属性外,另外还有一个奖金属性.请使用继承的思想设计出员工类和经理类.要求类中提供必要的方法进行属性访问.
class Demo24//设计出员工类和经理类.
{
public static void main(String[] args)
{
Employee worker=new Employee("张三","001",5000);
worker.work();
System.out.println(worker.getName());
Employee manager=new Manager("李四","007",5000,10000);
manager.work();
System.out.println(manager.getName());
}
}
class Employee
{
private String name;
private String ID;
private double salary;
Employee(){}
Employee(String name,String ID,double salary)
{
this.name=name;
this.ID=ID;
this.salary=salary;
}
public void work()
{
System.out.println("员工工作...");
}
public String getName()
{
return name;
}
public String getID()
{
return ID;
}
}
class Manager extends Employee
{
private String name;
private String ID;
private double salary;
private double fenhong;
Manager(String name,String ID,double salary,double fenhong)
{
super(name,ID,salary);
this.fenhong=fenhong;
}
public void work()
{
System.out.println("经理工作中...");
}
}
---------- java ----------
员工工作...
张三
经理工作中...
李四
Output completed (0 sec consumed) - Normal Termination
25.在一个类中编写一个方法,这个方法搜索一个字符数组中是否存在某个字符,如果存在,则返回这个字符在字符数组中第一次出现的位置(序号从0开始算),否则返回-1.要搜索的字符数组和字符都以参数形式传递给该方法.如果传入的数组为null,应抛出IllegalArgumentException异常.在类的main方法中以各种可能出现的情况测试验证该方法编写是否正确.
class Demo25//要搜索的字符数组和字符都以参数形式传递给该方法
{
public static void main(String[] args)
{
try
{
char[] chs={'a','b','c','d','e'};
System.out.println(FindChar.findChar(chs,'c'));
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
}
class FindChar
{
public static int findChar(char[] chs,char c)
{
if(chs==null)
throw new IllegalArgumentException("参数异常");
for(int i=0;i<chs.length;i++)
{
if(c==chs[i])
return i;
}
return -1;
}
}
26.补足compare函数内的代码,不许添加其他函数.
class Demo26
{
public static void main(String[] args)
{
Circle cir1=new Circle(1.0);
Circle cir2=new Circle(2.0);
Circle cir;
cir=cir1.compare(cir2);
if(cir1==cir)
System.out.println("圆1的半径比较大");
else
System.out.println("圆2的半径比较大");
}
}
class Circle
{
private double radius;
public Circle(double r)
{
radius=r;
}
public Circle compare(Circle cir)
{
//程序代码块
if(this.radius>=cir.radius)
return this;
return cir;
}
}
12.package/import和jar包
12.1 package/import
Java引入了包机制,提供了类名的多层命名空间,用于解决类的命名冲突.类文件管理等问题.java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的库类单元.如果希望把一个类放在指定的包结构下,应该在java源程序的第一个非注释行放置如下格式代码:
package cn.itcast;
一旦在java源文件中使用了这个package语句,就意味着该源文件里定义的所有类都属于这个包.
位于包中的每个类的完整类名都应该是包名和类名的组合,如果其他人需要使用该包下的类,也应该使用报名加类名的组合.
位于包中的类,在文件系统中也必须有与包名层次相同的目录结构.
编译源文件时使用的dos命令为 javac -d . className ,-d后代表要存放生成字节码文件的地址.如果默认为当前目录则用点.表示.
同一个包里的类不必位于相同的目录下.只要将classpath环境变量里包含这两个路径即可.
java的包机制需要两个方面的保证:1.源文件中使用package语句指定2.class必须放在对应路径下
一个源文件只能指定一个package
如果没有显示指定package,则放在默认包下
同一个包下的类可以自由访问,不许要增加前缀
如果创建处于其他包下类的实例,则在调用构造器时也需要使用包前缀.
为了简化编程.java引入了import关键字,import可以向某个java文件中导入指定包含层次下某个类或全部类.import语句应该出现在package之后,类名之前.
一旦在java源文件中使用import语句来导入指定类,在该源文件中使用这些类时就可以省略包前缀
在一些特殊情况下,如果不同的两个包内有两个类名相同的类,这时只能使用类的全名.
JDK1.5以后增加了import static 语句,静态导入有两种用法:1.用于导入指定类的单个静态Field/方法.2导入导入指定类的全部静态方法/Field.
用一句话归纳import 与import static:
import可以省略包名,import static可以省略类名.
12.2 jar包
12.2.1jar包基本概念
jjar的全称是java archive file,意思是java归档文件.通常jar是一种压缩文件,与常见的zip格式兼容但是要多一个名为meta-inf/manifest.mf清单文件.这个清单文件在生成jar文件时由系统自动生成.
使用jar包的好处
u 安全.能够对jar文件进行数字签名
u 加快下载速度.在网上使用applet时,如果存在多个文件而不打包,为了能够把每个文件都下载到客户端,需要为每个文件单独建立一个单独的http连接,很费事.将这些文件压缩成一个jar 包,只要建立一次http连接就可以一次下载所有文件
u 压缩.使文件变小,jar的压缩机制和zip完全相同
u 包封装.能够让jar包里面的文件依赖于统一版本的类文件.
u 可移植性.jar包作为内嵌在java平台内部处理的标准,能够在各种平台上直接使用
12.2.2配置可执行jar包
生成jar包常见命令:
u 创建JAR文件:jar cf test.jar test
u 创建jar文件,并显示压缩过程:jar cvf test.jar test
u 不使用清单文件:jar cvfM test.jar test
u 使用自定义清单文件:jar cvfm test.jar a.txt test
u 查看jar包内容:jar tf test.jar
u 查看jar包详细内容:jar tvf test.jar
u 解压缩:jar xf test.jar
u 带提示信息解压缩:jar xvf test.jar
u 更新jar文件:jar uf test.jar Hello.class
u 更新时显示详细信息:jar uvf test.jar Hello.class
创建可执行jar包
一个java程序的发布大致有三种方式
u 使用平台相关的编译器,将整个应用编译成平台相关的可执行文件
u 为应用编辑一个批处理文件
u 将应用程序制作成jar包
创建一个可执行jar包关键是让程序知道那个是程序的入口.可以通过jar命令的-e选项来完成.命令如下:
jar cvfe test.jar Test*.class
上面命令把当前目录下所有的class文件压缩到jar包中,并制定使用Test类作为程序的入口..
当创建jar包时,所有的类都必须放在与包结构对应的目录结构中.
13.枚举类
在java5开始,新增加了一个关键字enum,它和class/interface的地位相同,用于定义一个枚举类.
u 枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.enum类,而并没有直接继承了java.lang.Object类,当然java.lang.enum类继承了java.lang.Object类.
u 使用enum定义/非抽象的枚举类,会默认使用final修饰,因此枚举类不能派生子类
u 枚举类的构造器只能使用private修饰.,如果省略了,那么默认的为private修饰.
u 枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例.列出这些实例时系统会默认加上public static final 修饰.
u 所有的枚举类都提供了一个values方法,该方法可以很方便的遍历所有的枚举值.
//switch 语句里面可以放枚举值
下面代码演示了最基本的枚举的应用
class EnumDemo//演示枚举类的基本应用
{
public static void main(String[] args)
{
testEnum(Season.SPRING);
testEnum(Season.SUMMER);
testEnum(Season.FALL);
testEnum(Season.WINTER);
for(Season s:Season.values())
{
System.out.println(s);
}
}
public static void testEnum(Season e)
{
switch(e)
{
case SPRING:
System.out.println("春天");break;
case SUMMER:
System.out.println("夏天");break;
case FALL:
System.out.println("秋天");break;
default:
System.out.println("冬天");
}
}
}
enum Season
{
SPRING,SUMMER,FALL,WINTER;
}
运行结果:
---------- java ----------
春天
夏天
秋天
冬天
SPRING
SUMMER
FALL
WINTER
Output completed (0 sec consumed) - Normal Termination
下面代码演示了switch()放入this关键字的列子:
class EnumSwitchDemo//该类演示了在枚举类中switch中使用this关键字的情况
{
public static void main(String[] args)
{
Sex s=Enum.valueOf(Sex.class,"FAMALE");
s.setName("女");
System.out.println(s.getName());
s.setName("男");
System.out.println(s.getName());
}
}
enum Sex//定义一个性别的枚举类
{
FAMALE,MALE;
private String name;
public void setName(String name)
{
switch(this)
{
case FAMALE:this.name=name;break;
case MALE:this.name=name;break;
}
}
public String getName()
{
return name;
}
}
---------- java ----------
女
男
Output completed (0 sec consumed) - Normal Termination