面对对象第十天

---------------------- android培训java培训、期待与您交流! ----------------------

  (一)异常-finally

还是用之前的除以负数的那个例子:

class FuShuException extends Exception
{
    FuShuException(String msg)
    {
        super(msg);
    }
}
class Demo
{
    int div(int x,int y)throws FuShuException
    {
        if(y<0)
            throw new FuShuException("除以负数了");
        return x/y;
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {
        Demo d=new Demo();
        try
        {
            int x=d.div(4,-1);//上面div声明了,所以这里要try检测
            System.out.println("x="+x);
        }
        catch(FuShuException f)
        {
            System.out.println(f.toString());
        }
        finally
        {
            System.out.println("finally");//finally块里面是一定会执行的代码,不管出不出现异常都会执行
        }
        System.out.println("over");
    }
}

finally块中的代码是一定会执行的,不管任何情况都会执行,不管是发生异常还是不发生异常都会执行,另外,注意:假如我在catch块的最后加上return;表示到此结束主函数的运行,但是还是会运行finally块,比如:

public static void main(String[] args)
    {
        Demo d=new Demo();
        try
        {
            int x=d.div(4,-1);
            System.out.println("x="+x);
        }
        catch(FuShuException f)
        {
            System.out.println(f.toString());
            return;
        }
        finally
        {
            System.out.println("finally");//finally块里面是一定会执行的代码,不管出不出现异常都会执行
        }
        System.out.println("over");
    }

由于catch块中加入了return;那么打印完异常信息主函数就停止了,不会打印over,但是会打印finally.

这种一定会执行的代码块有什么存在意义呢,比如操作数据库的时候,为了不浪费数据库的资源,用户在访问完数据库之后必须要和数据库断开连接,这样别的用户才能继续访问数据库.比如:

public void method()
{
    连接数据库;
    数据操作;//throw new SQLException
    关闭数据库;
}

在进行数据操作的时候可能会发生诸如要访问的数据不存在等一系列异常问题,这时程序就会停止运行,但是停止之后就不会执行关闭数据库了,所以关闭数据库是必须要执行的,那此时关闭数据库的操作就要用到flnally代码块了,因为不管出现什么问题,关闭数据库的连接是必须要执行的.所以应该是这样:

public void method()
{
    try
    {
        连接数据库;
        数据库操作;
    }
    catch (SQLException s)
    {
    
    }
    finally
    {
        关闭数据库;
    }
}

小结:finally代码块是一定会执行的语句,通常用于关闭资源.

小知识:分层思想:在上面的数据库操作的例子中,当检测到数据库操作异常之后,catch里面要捕获那个异常并进行处理,捕获到的是SQLException,这个异常用户是不能处理的,只能是开发者处理,所以catch的第一行写上开发者如何对数据库异常的处理方式,但除了属于数据库层面的异常以外还有属于用户层面的异常,比如我存储数据的时候,数据库异常了,数据库的异常就开发者处理,而此时数据到底能否存储,这个问题应该抛给我,我来处理这个问题,能存储,那我继续存储,不能,我就走人,而这个问题也可以封装成一个异常类,并抛给用户自行处理.所以catch第二行就抛出这个异常,并在函数后面throws声明.这就是分层思想,不同分工.

class NoException extends Exception
{
    NoException()
    {
        super();
    }
}
public void method()throws NoException
{
    try
    {
        连接数据库;
        数据库操作;
    }
    catch (SQLException s)
    {
        对数据库异常的处理;
        throw new NoException();
    }
    finally
    {
        关闭数据库;
    }
}


  (二)异常-处理语句其他格式

第一种格式:

try

catch

或者

try

catch

catch

......

第二种格式:

try

catch

finally

第三种格式:

try

finally

 

先判断几种抛出和捕获的情况能否在编译的时候通过:

1.class Demo
{
    public void method()
    {
        throw new Exception();
    }
}

不能,throw了之后没有在函数后面throws声明.

2.class Demo
{
    public void method()
    {
        try
        {
            throw new Exception();
        }
        catch(Exception e)
        {
        }
    }
}

能,因为抛出和捕获动作都在一个函数内部完成了,有catch就是问题被解决了。

3.class Demo
{
    public void method()
    {
        try
        {
            throw new Exception();
        }
        catch(Exception e)
        {
            throw e;
        }
    }
}

不能,throw抛出e之后,函数后面没声明.

4.

class Demo
{
    public void method()
    {
        try
        {
            throw new Exception();
        }
        catch(Exception e)
        {
            try
            {
                throw e;
            }
            catch(Exception f)
            {
            }            
        }
    }
}

能,抛出e之后,又在函数内部捕获了.注意此时的f不能写成e了,不然会提示已经在method()内部定义了e.


那么try-finally有什么应用呢,比如我定义了一个功能,里面抛出一个异常,但是这个功能不能处理这个异常,要抛给别人来处理,而且这个功能在抛出异常后必须要关闭资源,所以此时try后面就不是catch而是finally.

class Demo
{
    public void method()throws Exception
    {
        try
        {
            throw new Exception();
        }
        finally
        {
            关闭资源;
        }
    }   
}


  (三)覆盖时的异常特点

异常在子父类覆盖中的体现:

1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类抛出的异常或者该异常的子类或者不抛,不能抛父类中没有的异常。

class AException extends Exception
{
}
class BException extends AException
{
}
class CException extends Exception
{
}
class Fu
{
    void show()throws AException
    {
        
    }
}
class Zi extends Fu
{
    void show()throws AException
    {}
}
class Test
{
    void function(Fu f)//父类引用
    {
        try
        {
            f.show();
        }
        catch (AException e)
        {
        }
    }

}
class Demo
{
    public static void main(String[] args)
    {
        Test t=new Test();
        t.function(new Zi());//注意写法
    }
}

注意:

1.创建谁的对象,就调用谁的方法。这里创建的是子类对象,所以在调用show()方法的时候就调用的是Zi里面的show()。

2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,那么只能抛出父类异常的子集.

假如父类抛出了A,B,C,D,E五个异常,那么子类只能抛出abcde,abcd,abc.....,或者是这些异常的子类异常,换句话说就是父类抛出的异常。

3.如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常,就必须要try-catch,绝对不能抛。


  (四)异常-练习

/*
有一个圆形和长方形,
都可以获取面积,对于面积如果穿线非法的数值,比如零和负数,视为是回获取面积出现问题,通过异常来表示问题。
先对这个程序进行基本的设计。
*/
interface Shape//定义一个获取面积的接口
{
    void getArea();
}
class Rec implements Shape//描述这个矩形,并定义获取面积
{
    private int len,wid;
    Rec(int len,int wid)
    {
        this.len=len;
        this.wid=wid;
    }
    public void getArea()
    {
        System.out.println(len*wid);
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {
        Rec r=new Rec(3,4);//传入数值,计算面积
        r.getArea();
    }
}

此时考虑如何定义异常,因为当用户输入错误数据后,应该提示错误信息。

class NoValueException extends Exception//定义新的非法值异常
{
    NoValueException(String message)
    {
        super(message);
    }
}
interface Shape//获取面积接口
{
    void getArea();
}
class Rec implements Shape//描述矩形长宽并定义获取面积
{
    private int len,wid;
    Rec(int len,int wid)throws NoValueException
    {
        if(len<=0||wid<=0)
            throw new NoValueException("出现非法值");
        this.len=len;
        this.wid=wid;
    }
    public void getArea()
    {
        System.out.println(len*wid);
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {
        try
        {

            //注意这两句代码要写在try里面,否则会提示找不到r,一个引用只在一个代码块中有效。另外上面哪个函数后面throws了,那么try里面就要写哪个函数。
            Rec r=new Rec(-3,4);
            r.getArea();
        }
        catch (NoValueException n)
        {
            n.printStackTrace();
        }
    }
}

小结:所以说要写在try里面的东西有两个,一个就是上面throws的那个函数,如果要调用,要写在try里面,还有就是与这个函数有关的变量,要用到这个变量的语句也要写在try里面。


上面新异常继承的是Excetpion,而当输入错误数值的之后,希望程序停止运行,所以就应该继承RunTimeExcetpion。

class NoValueException extends RuntimeException
{
    NoValueException(String msg)
    {
        super(msg);
    }
}
interface Shape
{
    void getArea();
}
class Rec implements Shape
{
    private int len,wid;
    Rec(int len,int wid)
    {
        if(len<=0||wid<=0)
            throw new NoValueException("出现非法值");    
        this.len=len;
        this.wid=wid;
    }
    public void getArea()
    {
        System.out.println(len*wid);
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {        
            Rec r=new Rec(-3,4);
            r.getArea();
            System.out.println("over");
    }
}


圆面积同理

class NoValueException extends RuntimeException
{
    NoValueException(String msg)
    {
        super(msg);
    }
}
interface Shape
{
    void getArea();
}
class Rec implements Shape
{
    private int len,wid;
    Rec(int len,int wid)
    {
        if(len<=0||wid<=0)
            throw new NoValueException("出现非法值");    
        this.len=len;
        this.wid=wid;
    }
    public void getArea()
    {
        System.out.println(len*wid);
    }
}
class Circle implements Shape
{
    private int radius;
    public static final double Pai=3.14;//全局常量
    Circle(int radius)
    {
        if(radius<=0)
            throw new NoValueException("出现非法值");
        this.radius=radius;
    }
    public void getArea()
    {
        System.out.println(radius*radius*Pai);
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {        
            Rec r=new Rec(-3,4);
            r.getArea();
            Circle c=new Circle(-8);
            System.out.println("over");
    }
}

注意:

1.上面的public static final double Pai=3.14,是全局常量,而且权限最大,通常遇到像这类可能整个程序都会使用的常量,就使用这种写法。

2.上面的NoValueException类可以不用创建,在定义长方形和圆形面积的时候,可以直接new RuntimeException("出现非法值");但是这样结果都是提示出现RuntimeException异常,这样就不知道到底出现的是什么类型的异常,所以最好要自定义一个异常类,方便阅读。


  (五)异常-总结

注意:不是说finally代码块里面的东西就一定是会执行的,有一种特例。比如

class FuShuException extends Exception
{
    FuShuException(String msg)
    {
        super(msg);
    }
}
class Demo
{
    int div(int x,int y)throws FuShuException
    {
        if(y<0)
            throw new FuShuException("除以负数了");
        return x/y;
    }
}
class ExceptionDemo
{
    public static void main(String[] args)
    {
        Demo d=new Demo();
        try
        {
            int x=d.div(4,-1);
            System.out.println("x="+x);//注意:这行是不会执行的,try只会检测抛出异常的那个方法,一旦检测到出了问题就直接跳转执行catch,如果正常就继续执行打印x。

        }
        catch(FuShuException f)
        {
            System.out.println(f.toString());
            System.exit(0);//表示系统退出,jvm结束。
        }
        finally
        {
            System.out.println("finally");
        }
        System.out.println("over");
    }
}

小结:finally前面的catch块最后一行是System.exit(0);,这个表示系统退出,jvm结束,那么后面的代码块就不会执行了,不管是不是finally。那么说,finally前面那个块的最后一行如果是return,那么fianlly块会执行,但是fianlly块后面的就不会执行了,如果finally块前面那个块的最后一行是System.exit(0);那么程序就到此为止了,这个块后面的都不会执行。


异常的处理原则:

1.两种处理方式:try或者throws

2.当调用抛出异常的功能时,抛出几个就处理几个,一个try可以对应多个catch,有多个catch时,父类catch放在最下面。

3.在catch内,需要定义针对性处理方式,不要简单写输出语句,也不要不写。

4.当捕获到异常,本功能处理不了时,可以继续在catch中抛出。比如

class Demo
{
    public void method()throws AException
    {
        try
        {
            throw new AException();
        }
        catch (AException a)
        {
            throw a;
        }
    }    
}

5.如果该异常处理不了,但并不属于该功能出现的异常,可以将异常转换后,再抛出和该功能相关的异常。比如

class Demo
{
    public void method()throws BException
    {
        try
        {
            throw new AException();
        }
        catch (AException a)
        {
            throw new BException();
        }
    }    
}

6.或者异常可以处理,但需要将异常产生后和本功能相关的问题提供出去,让调用者知道,并处理,也可以将捕获异常处理后,转换新的异常抛出。比如,数据库出问题了,是A异常,我处理完了,但是数据没存成功,这是B异常,我还得抛给调用者,让调用者知道并让其自己处理。上面的情况5就是数据库的问题我也处理不了,但不能抛给调用者,但我还是得把数据没存成功的异常抛给调用者让其自己处理。比如存款也是一样,假如存钱的时候出了问题,机器故障是一个异常,机器机子处理完后,再把没存成功的异常抛给我,我来处理这个异常,可以是再存一次或者不存了。

class Demo
{
    public void method()throws BException
    {
        try
        {
            throw new AException();
        }
        catch (AException a)
        {
            对AException进行处理;
            throw new BException();
        }
    }    
}


  (六)练习四

看看下面几段代码是否正确,结果是什么,错在哪?

1.

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");
    }
}

注意:主函数检测到func()有异常后会直接去找处理方法,所以执行完finally之后,不是去打印A,而是直接去执行catch,打印C,所以结果是

B

C

D

---------------------------------------------------------------------------------------------------------------------------

2.

class Test
{
    Test()
    {
        System.out.println("A");
    }
}
class Demo extends Test
{
    Demo()
    {
        System.out.println("B");
    }
    public static void main(String[] args)
    {
        new Demo();
        new Test();
    }
}

注意:子类构造函数的第一行都有一个隐式的super,所以

Demo()
    {
        System.out.println("Demo");
    }

的第一行其实是这样

Demo()
    {
        super();
        System.out.println("Demo");
    }

所以先执行的是打印A,结果是

A

B

A

---------------------------------------------------------------------------------------------------------------------------

3.

interface A{}
class B implements A
{
    public String func()
    {
        return "func";
    }
}
class Demo
{
    public static void main(String[] args)
    {
        A a=new B();
        System.out.println(a.func());
    }
}

由于接口A里面没有定义func方法,所以编译失败。

正确的作法应该是在接口A里面定义func方法,注意不要带方法体。

interface A
{
    public String func();
}
class B implements A
{
    public String func()
    {
        return "func";
    }
}
class Demo
{
    public static void main(String[] args)
    {
        A a=new B();
        System.out.println(a.func());
    }
}

---------------------------------------------------------------------------------------------------------------------------

4.

class Fu
{
    boolean show(char a)
    {
        System.out.println(a);
        return true;
    }
}
class Demo extends Fu
{
    public static void main(String[] args)
    {
        int i=0;
        Fu f=new Demo();
        Demo d=new Demo();
        for(f.show('A');f.show('B')&&(i<2);f.show('C'))
        {
            i++;
            d.show('D');
        }
    }
    boolean show(char a)
    {
        System.out.println(a);
        return false;
    }
}

在执行for循环的时候,先执行f.show('A'),调用子类也就是Demo的show方法,打印A,并返回false,接着执行f.show('B')&&(i<2);,打印B并且返回false,由于是&&,所以当有一个是false就不会满足条件,所以循环到此结束,整个程序到此结束。结果是

A

B

---------------------------------------------------------------------------------------------------------------------------

5.

interface A
{
    public String test();
}
class B implements A
{
    public String test()
    {
        return "yes";
    }
}
class Demo
{
    static A get()
    {
        return new B();
    }
    public static void main(String[] args)
    {
        A a=get();
        System.out.println(a.test());
    }
}

注意写法,

static A get()
    {
        return new B();
    }
    public static void main(String[] args)
    {
        A a=get();

A接口类型的引用指向了get(),而运算结果是B类对象,这也是多态,就相当于A a=new B();所以最后结果是

yes

---------------------------------------------------------------------------------------------------------------------------

6.

class Super
{
    int i=0;
    public Super(String a)
    {
        System.out.println("A");
        i=1;
    }
    public Super()
    {
        System.out.println("B");
        i+=2;
    }
}
class Demo extends Super
{
    public Demo(String a)
    {
        System.out.println("C");
        i=5;
    }
    public static void main(String[] args)
    {
        int i=4;
        Super d=new Demo("A");
        System.out.println(d.i);
    }
}
注意:当遇到子父类的情况,在调用子类的构造函数的时候,一定不要忘了子类构造函数的第一行有隐式的super();,所以最后结果是

B

C

5

---------------------------------------------------------------------------------------------------------------------------

7.

interface Inter
{
    void show(int a,int b);
    void func();
}
class Demo
{
    public static void main(String[] args)
    {
       补足代码,调用两个函数,要求使用匿名内部类。
    }
}

注意:接口里面的成员都是公有,所以在写内部类里面的方法时不要忘了写public,结果是

interface Inter
{
    void show(int a,int b);
    void func();
}
class Demo
{
    public static void main(String[] args)
    {
        Inter i=new Inter()
        {
            public void show(int a,int b){}
            public void func(){}
        };
        i.show(4,3);
        i.func();
    }
}

---------------------------------------------------------------------------------------------------------------------------

8.

class TD
{
    int y=6;
    class Inner
    {
        static int y=3;
        void show()
        {
            System.out.println(y);
        }
    }
}
class TC
{
    public static void main(String[] args)
    {
        TD.Inner ti=new TD().new Inner();
        ti.show();
    }
}

编译失败,因为内部类Inner中出现了静态成员y,而内部类Inner前面并没有加静态修饰,所以编译失败。

非静态的内部类中不可以定义静态成员。内部类中如果定义了静态成员,那么该内部类必须被静态修饰。

---------------------------------------------------------------------------------------------------------------------------

9.

选择题:写出错误答案错误的原因,用单行注释的方式。
class Demo
{
    int show(int a,int b)
    {
        return 0;
    }
}
下面哪些函数可以存在于Demo的子类中。
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 Fu
{
    int num=4;
    void show()
    {
        System.out.println("showFu");
    }
}
class Zi extends Fu
{
    int num=5;
    void show()
    {
        System.out.println("ShowZi");
    }
}
class Demo
{
    public static void main(String[] args)
    {
        Fu f=new Zi();
        Zi z=new Zi();
        System.out.println(f.num);
        System.out.println(z.num);
        f.show();
        z.show();
    }
}

结果是:

4

5

showZi

showZi

---------------------------------------------------------------------------------------------------------------------------

12.

interface A
{
    void show();
}
interface B
{
    void add(int a,int b);
}
class C implements A,B
{
    //补全代码
}
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 a,b;
    public void add(int a,int b)
    {
        this.a=a;
        this.b=b;
    }
    public void show()
    {
        System.out.println(a+b);
    }
}
class D
{
    public static void main(String[] args)
    {
        C c=new C();
        c.add(4,2);
        c.show();
    }
}

---------------------------------------------------------------------------------------------------------------------------

13.

class Demo
{
    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();
    }
}

结果是

B

C

D

---------------------------------------------------------------------------------------------------------------------------

14.

class Super
{
    int i= 0;
    public Super(String s)
    {
        i=1;
    }
}
class Demo extends Super
{
    public Demo(String s)
    {
        i=2;
    }
    public static void main(String[] args)
    {
        Demo d=new Demo("yes");
        System.out.println(d.i);
    }
}

编译失败,要么在Super类中写一个空参数的Super(){};要么在public Demo(String s)的方法体的第一行写上super("A");以和 public Super(String s)对应。

---------------------------------------------------------------------------------------------------------------------------

15.

class Super
{
    public int get(){return 4;}
}
class Demo extends Super
{
    public long get(){return 5;}
    public static void main(String[] args)
    {
        Super s=new Demo();
        System.out.println(s.get());
    }
}

编译失败,因为子父类的get方法的返回值类型不一致,无法覆盖。

---------------------------------------------------------------------------------------------------------------------------

16.
class Demo
{
    public static void func()//注意:由于主函数要调用,所以这个函数加了静态
    {
        try
        {
            throw new Exception();
            System.out.println("A");
        }
        catch (Exception e)
        {
            System.out.println("B");
        }
    }
    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");
        }

在try里面,第一行抛出一个异常,那么这个时候表示try肯定检测到了异常,那么就不会执行System.out.println("A");,而会直接跳转执行catch,等于说这句就是废话,所以编译会失败,注意在throw,return,break后面都不要再写语句了,当然是指在一个代码块里面,因为再写的语句不会执行到,属于废话,所以这样编译会失败。

对比13题,为什么会编译成功,就是因为这道题把异常封装在了一个静态方法里面,只是对外暴露了声明,说这个函数可能有问题需要调用者检测,当然,此处是静态是因为主函数会调用这个函数,所以在try的时候写的是调用这个可能有问题的函数,所以后面的 System.out.println("A");是有可能执行也有可能不会执行,所以编译是能通过的。

---------------------------------------------------------------------------------------------------------------------------

17.

class Demo
{
    public void func()
    {
        //位置1;
    }
    class Inner{}
    public static void main(String[] args)
    {
        Demo d=new Demo();
        //位置2
    }
}
A.在位置1写 new Inner();//正确,外部类要访问内部类必须建立内部类对象
B.在位置2写 new Inner();//错误,因为主函数是静态的,要访问内部类也必须是静态的。
C.在位置2写 new d.Inner();//错误,这个就相当于new new Demo().Inner();格式错误
D.在位置2写 new Demo.Inner(); //错误,如果要这样写,那么就是Demo类名调用Inner();,那么 Inner就应该是静态的。

---------------------------------------------------------------------------------------------------------------------------

18.

class Exc0 extends Exception{}
class Exc1 extends Exception{}
class Demo
{
    public static void main(String[] args)
    {
        try
        {
            throw new Exc1();
        }
        catch (Exception e)
        {
            System.out.println("B");
        }
        catch(Exc0 e)
        {
            System.out.println("A");
        }
    }
}

错误在于多个catch,父类catch写在最下面。

---------------------------------------------------------------------------------------------------------------------------

19.

interface Test
{
    void func();
}
class Demo
{
    public static void main(String[] args)
    {
        //补足代码,匿名内部类        
    }
    void show(Test t)
    {
        t.func();
    }
}

思路如下:

1.补足代码处肯定是调用show方法,注意,但是不能直接调用,因为主函数是静态的,show也必须是静态的,但这里show不是静态的,所以只能用建立对象的方式调用。就是new Demo().show()。

2.show方法的参数是Test类型,而Test是接口,那么要调用func方法,就得创建一个新的类实现func,这里要求是匿名内部类,所以最后结果是

interface Test
{
    void func();
}
class Demo
{
    public static void main(String[] args)
    {
        new Demo.show(new Test()
        {
            public void func()
            {
                System.out.println("A");
            }
        });        
    }
    void show(Test t)
    {
        t.func();
    }
}

---------------------------------------------------------------------------------------------------------------------------

20.

class Test
{
    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);
        foo(1);
        System.out.println(output);
    }
}

注意:当执行完

foo(0);
        System.out.println(output);后,output的值是134,而不是空字符串,所以在执行

 foo(1);
        System.out.println(output);的时候,是"134"+"2",而不是空字符串+"2"。

最后的结果是

134

13423

---------------------------------------------------------------------------------------------------------------------------

21.

就是(四)异常-练习里面的那个求面积题。

---------------------------------------------------------------------------------------------------------------------------

22.

//补足compare函数内的代码,不许添加其他函数
class Circle
{
    private static double pi=3.14;
    private double radius;
    public Circle(double r)
    {
        radius=r;
    }
    public static double compare(Circle[] cir)
    {
        //补足代码,其实就是在求数组中的最大值。
    }
}
class TC
{
    public static void main(String[] args)
    {
        Circle cir[]=new Circle[3];//注意:创建一个Circle类型数组,当然标准写法是Circle[] cir=new Circle[3];,类类型的数组初始化值是null,int类型的初始化值是0。
        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)
    {
        int max=0;
        for(int x=1;x<cir.length;x++)
        {
            if(cir[x].radius>cir[max].radius)
                max=x;
        }
        return cir[max].radius;
    }
}
class TC
{
    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));
    }
}

小结:这道题的求最大值方式其实就是把不同的对象赋值给数组中的元素,然后利用求数组最值的方式,求出对象值最大的那个对象。

---------------------------------------------------------------------------------------------------------------------------

23.

class Demo
{
    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);
    }
}

||有点特殊,当左边是真右边就不运算了,所以只运算了methodB(4);,结果是4.

---------------------------------------------------------------------------------------------------------------------------

24.

假如我们在开发一个系统时需要对员工进行建模,员工包含3个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另外还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

答案见面对对象第七天(十)抽象类练习。

---------------------------------------------------------------------------------------------------------------------------

25.

在一个类中编写一个方法,这个方法搜索一个字符数组中是否存在某个字符,如果存在,则返回这个字符在字符数组中第一次出现的位置(序号从0开始计算),否则,返回-1 。要搜索的字符数组和子都都以参数形式传递给该方法,如果传入的数组位null,应抛出IllegalArgumentException异常。在类的main方法中以各种可能出现的情况测试验证该方法编写得是否正确,例如,字符不存在,字符存在,传入的数组位null等。

注意:IllegalArgumentException是RuntimeException的子类,所以不需要抛,也不需要try-catch。

class Demo
{
    public int getIndex(char[] arr,char key)
    {
        if(arr==null)
            throw new IllegalArgumentException("数据异常,数组为空");
        for(int x=0;x<arr.length;x++)
        {
            if (arr[x]==key)
                return x;
        }
        return -1;        
    }
    public static void main(String[] args)
    {
        char[] arr={'1','2','3','A'};
        System.out.println(new Demo().getIndex(arr,'B'));
    }
}
小结:

1.返回值是可以被直接打印输出的,返回什么就打印什么。

2. return -1;应该写在for循环外面,要是写在里面会提示getIndex没有返回值。

3.数组的写法一个就是char[] arr=new char[4];,一个就是char[] arr=new char[]{'1','2','3','A'};,或者简写成char[] arr={'1','2','3','A'};,所以

public static void main(String[] args)
    {
        char[] arr={'1','2','3','A'};
        System.out.println(new Demo().getIndex(arr,'B'));
    }

也可以写成

public static void main(String[] args)
    {
        System.out.println(new Demo().getIndex(new char[]{'1','2','3','A'},'A'));
    }

但是别写成

public static void main(String[] args)
    {
        System.out.println(new Demo().getIndex({'1','2','3','A'},'A'));
    }

---------------------------------------------------------------------------------------------------------------------------

26.

//补足compare函数内的代码,不许添加其他函数。
class Circle
{
    private double radius;
    public Circle(double r)
    {
        radius=r;
    }
    public Circle compare(Circle cir)
    {
        //补足代码
    }
}
class TC
{
    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的半径比较大");
    }

}

这个其实就是在比较两个对象的半径大小,cir1.compare(cir2);,cir1.radius是否>cir2.radius,但是这里的cir1应该用this表示,另外考虑到时比较大小,可以用三元运算符表示,所以结果是

public Circle compare(Circle cir)
    {
        //补足代码
        return(this.radius>cir.radius)?this:cir;
    }

注意这里三元运算符的写法


 (七)包package

包就类似文件夹,主要是为了区分同名类文件,假如两个java文件里面有同名的类,那就得分开存储这两个同名类文件了。

注意:定义包使用package这个关键字,包的名称所有字母都要小写,另外要定义在整个程序的第一行。比如

package pack;
class Demo
{
    public static void main(String[] args)
    {
        System.out.println("ABC");
    }
}

编译正常,但是运行的时候就会报错了,提示(wrong name:),说是类名称错误,所以应该在运行的时候在cmd中这样输命令java pack.Demo,但是会提示找不到类,原因是没有pack文件夹,所以新建一个pack文件夹,再把Demo.class文件丢进去再使用java pack.Demo就能正常运行了。但是这样非常麻烦,不可能每次都新建一个文件夹,所以在编译的时候就通过命令来自动创建文件夹。应该这样:

javac -d . 01.java

java pack.Demo

注意:-d表示directory,目录的意思,点表示当前目录,不要漏掉-d和点之间,点和01之间的空格。

这样就在编译的时候在当前目录下创建了一个pack文件夹,编译后的class文件就存放在这个文件夹中,那么在运行的时候就可以直接使用java pack.Demo来运行。之所以之前在编译的时候没有写pack,是因为java默认就是把当前目录作为包,所以在当前目录生成class文件。


当然也可以在编译的时候指定其他目录存放class文件,比如

javac -d h: 01.java,在H盘下生成一个pack文件夹来存放class文件,但是在运行的时候假如不是在H盘下,那么就会提示找不到类。因为class path不是H盘下,在cmd输入set classpath查看classpath,如果不正确,那么就输入set classpath=h:\,注意不要漏掉后面的\,如果是盘符下面的文件夹,就不用那个斜杠了,去看窗口地址栏就知道该怎么写了,然后再运行class文件,也就是java pack.Demo。

小结:

1.如果在写代码的时候第一行写了package,那么在编译的时候一定要-d指定路径,点是当前路径。

2.在运行的时候也要注意在类名前加上包名.,另外还得注意classpath是否正确。classpath应该是包名文件夹的上一级目录。

3.所以包的好处就是把类文件和java文件分开存,便于管理。


  (八)包与包之间访问

同一个包中的类之间进行访问是通过创建对象,而不同包中的类之间进行访问也可以通过创建对象。

比如,一个java文件里面的某个函数要调用另一个java文件里面的某个函数:

先写一个包

package pack2;
class  Demo2
{
    void show()
    {
        System.out.println("Demo2");
    }
}
然后再写一个包来调用这个show

package pack1;
class Demo1
{
    public static void main(String[] args)
    {
        Demo2 d=new Demo2();
        d.show();
    }
}

---------------------------------------------------------------------------------------------------------------------------

由于主函数实在pack1里面,当然先编译pack2才能编译pack1,编译pack2成功,但是在编译pack1的时候提示找不到Demo2,因为类名错误,正确的应该是包名.类名。所以

package pack1;
class Demo1
{
    public static void main(String[] args)
    {
        pack2.Demo2 d=new pack2.Demo2();
        d.show();
    }
}

---------------------------------------------------------------------------------------------------------------------------

还是报错,提示Demo2不是公共的。这里需要说下,如果在编译pack2的时候-d后面的路径和set classpath一致,那么编译pack2所生成的pack文件夹就在指定路径下,在编译pack1的时候就不会报错说找不到软件包pack2,因为编译pack1需要用到pack2的class文件,而pack2的class文件在setpath的pack下,是正确的路径。

由于提示Demo2在pack2中不是公共的,无法从外部程序包中对其进行访问,所以需要将Demo2前面加上public。

package pack2;
public class Demo2
{
    void show()
    {
        System.out.println("Demo2");
    }
}

---------------------------------------------------------------------------------------------------------------------------

再编译pack2,但是此时会报错,提示类Demo2是公共的, 应在名为 Demo2.java 的文件中声明,原因是java的特性,要求如果在类前面加了public,那么保存的java文件名必须和加了public的类名一致,所以在保存pack2的时候,应该保存为Demo2.java。

---------------------------------------------------------------------------------------------------------------------------

再编译pack1,报错,提示show()在Demo2中不是公共的,无法从外部程序包中对其进行访问,因为类公有后,被访问的成员也要公有才能被访问,所以show前面也需要加public修饰。

package pack2;
public class Demo2
{
    public void show()
    {
        System.out.println("Demo2");
    }
}

---------------------------------------------------------------------------------------------------------------------------

再编译pack2,再编译pack1,再运行pack1,就能显示正确结果了。

---------------------------------------------------------------------------------------------------------------------------

接下来说说包与包之间的继承。

有一种情况是,比如有1,2,3三个包,2继承了3


package pack3;//注意别漏掉分号
public class Demo3
{
    public void method()
    {
        System.out.println("Demo3");
    }
}


package pack2;
public class Demo2 extends pack3.Demo3//注意别漏掉包名
{
    public void show()
    {
        System.out.println("Demo2");
        method();//注意继承之后可以直接调用父类中的方法
    }
}


package pack1;
class Demo1
{
    public static void main(String[] args)
    {
        pack2.Demo2 d=new pack2.Demo2();
        d.show();
    }
}

结果是

Demo2
Demo3

所以说继承在包与包之间是可行的。

---------------------------------------------------------------------------------------------------------------------------

但是,1也可以创建3的对象,直接调用3的method,不需要通过2继承3,再创建2的对象来访问3。

package pack1;
class Demo1
{
    public static void main(String[] args)
    {
        pack3.Demo3 d=new pack3.Demo3();
        d.method();
    }
}

所以这里介绍一种新的权限,protected,假如把3的method的public权限换成protected,那么1再通过创建3对象来调用method方法就会报错,这时可以让2继承3,并直接调用method,再在1里面创建2的对象,就能间接调用method了。因为不同包的子类可以直接访问父类中被protected的方法。

---------------------------------------------------------------------------------------------------------------------------

包与包之间调用小结:

1.类前面的修饰符有两种,一种是默认,什么都不写,一种是public。如果A包中的类要访问B包中的类,B包中的类前面要加public才有足够大的权限,B包类里面被访问的成员前面也要加public才有足够的权限。一旦B包中某个类前面加了public,那么保存的java文件的文件名要和加了public的这个类的类名一模一样。所以一个包中,不能出现两个或者两个以上的公有类或者公有接口。

2.java的package支持多层文件夹,多层之间用点隔开,也就是package pack3.A.B;

3.A包中的类要创建B包中的类的对象,要在写B包中那个类名前加上包名。

4.编译的时候先编译被访问的那个包,并且注意set classpath路径要包含有-d的路径,而且package定义的路径要和包名.类名里面的包名一致。

5.运行的时候要写java 包名.类名。

6.包与包之间能用的权限只有两种,一种是public,一种是protected。而且protected的成员只能被另外一个包中的子类访问。

7.权限总结:

                                  public                   prtected                             默认                            private

同包同类                    能                            能                                    能                                   能

同包不同类                能                            能                                    能                                  不能

同包子类                    能                            能                                    能                                  不能

不同包子类                能                            能                                   不能                               不能

不同包                        能                           不能                                不能                               不能

需要注意的是上面的权限说的是在调用的时候,同一个类中,或者子类调用父类,是直接调用,不同类中调用需要创建对象。但是子类覆盖父类的话,只需要子类那个函数的权限大于或者等于父类被覆盖的那个函数的权限即可,哪怕父类的那个函数的权限是private也是一样。


  (九)导入import

上面讲在定义包的时候能定义多层,但是在创建对象的时候需要写包名.类名,如果包名有很多层,那么在写包名.类名的时候会很繁琐。所以这里介绍新的关键字import。

import的作用就是省去包名.类名的繁琐。可以在开始就把需要创建对象的包名又特别长的类导入进来,这样在创建对象的时候就不用写包名了。

先写一个pack3

package pack3.a.b;
public class Demo3
{
    public void method()
    {
        System.out.println("Demo3");
    }
}

再写一个pack1

package pack1;
class Demo1
{
    public static void main(String[] args)
    {
        pack3.a.b.Demo3 d=new pack3.a.b.Demo3();
        d.method();
    }
}

如果使用import预先导入Demo3,就不需要在创建对象的时候写包名。

package pack1;
import pack3.a.b.Demo3;
class Demo1
{
    public static void main(String[] args)
    {
        Demo3 d=new Demo3();
        d.method();
    }
}

---------------------------------------------------------------------------------------------------------------------------

如果在包中或者是包中的其他路径中有多个类,这些都在同一路径下,则可以这样写,导入这个路径下全部类。

import pack3.a.b.*;

注意:假如a包中有一个类,b包中有一个类,不能用这种写法来同时导入两个类,比如

import pack3.a.*;,这样写只会导入a包中的所有类,正确的写法应该是

import pack3.a.*;

import pack3.a.b.*;

不过大多数情况下不要使用通配符来导入类,因为很多时候都不会使用全部的类,可能只是使用一两个,全部导入进来会占用不必要的资源。

---------------------------------------------------------------------------------------------------------------------------

另外在定义包名的时候尽量别定义重名的,即便是有重名的,也最好用url来定义,因为url是唯一的。比如

定义一个测试的包

package cn.itcast.demo;

定义一个练习的包

package cn.itcast.test;


  (十)jar包

jar包就是对包的压缩,比如把多个pack压缩成一个jar包,通过jar.exe来操作。

在cmd中输入jar能看到对jar的使用方法。

比如现在某个目录下有三个pack包,先在cmd中把当前目录切换到有这三个包的目录。

1.创建一个jar包:在cmd中输入jar -cf 123.jar pack1 pack2 pack3,这样就会在那个目录下创建一个jar文件。

2.查看jar包里面的东西:jar -tf 123.jar

注意:此时,如果删掉pack1, pack2, pack3这三个包,再运行java pack1.Demo1则会报错,但是,这三个包已经被压缩到一个jar包里面了,等于说这三个包的父目录变为了当前目录下的123.jar,所以此时需要将set classpath进行相应的更改,set classpath=.\123.jar,此时再运行java pack1.Demo1就会显示正确的结果了。所以如果我要使用别人写好的程序,只需要把别人的jar包拿来就行,放在classpath下即可。运行之前要看看classpath到底包含了哪些路径,这样好先把路径改成正确的。

3.在打包的时候显示详细信息:jar -cfv 123.jar pack1 pack2 pakc3,显示了压缩比。

4.显示详细信息和带时间的目录:jar -tfv 123.jar

---------------------------------------------------------------------------------------------------------------------------

当然在显示信息的时候可以使用命令把信息存储在txt文件里面,比如

jar -tfv 123.jar >h:\123.txt

就是在H盘下生成一个文件名是123的txt文件,里面存储这jar -tfv 123.jar生成的信息。

---------------------------------------------------------------------------------------------------------------------------

什么时候需要将信息存进txt文件呢?在E:\Software\JAVASE_JDK_7_u_2\jre\lib里面有一个rt.jar的文件,如果在cmd里面看信息会很长,需要将信息存进txt方便查看。先切换路径到E:\Software\JAVASE_JDK_7_u_2\jre\lib,再jar -ft rt.jar >h:\rt.txt,这个rt.jar是java的类库文件,里面存储着java的类。








---------------------- android培训java培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net/heima

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值