类的高级运用、异常、集合、文件读写、序列化、重写equals和hashCode方法实例

本文探讨了Java中类的高级用法,包括异常处理、集合操作如Vector和List,文件读写,以及对象序列化。同时,详细阐述了如何重写equals()和hashCode()方法,以确保对象比较的正确性和在哈希表中的行为。
摘要由CSDN通过智能技术生成

一、 package作为命令作为一个JAVA源文件的第一句。不同包中存在同名类,引入使用时用包名.类名来使用。星号形式可能会增加编译时间,对执行时间和类的大小绝对没用影响。

二、 抽象类:

class关键字前增加abstract修饰符,就可以蒋一个类定义成抽象类。抽象类除了能像普通类一样可以拥有一般的属性和方法,也可以拥有抽象方法。

1、   含有抽象方法的类必须声明成抽象类。

2、   抽象类不能被实例化,但是可以用来创建对象引用。

3、   不能定义抽象的构造方法和抽象的静态方法。

4、   所有的抽象类的子类都必须实现抽象类中的抽象方法或是他自己也声明成abstract

三、 接口使用

1、   接口类的访问权限只能是public或是默认修饰符。接口中的方法也只能是public或是默认的修饰符。

2、   接口的方法都是抽象方法。接口是抽象方法和常量值的定义的集合。即变量默认都是public static final修饰的。就口中的方法只能声明不能有具体的实现。

3、   如果接口本身定义成public,所有方法和变量都是public的。

4、   实现接口的类要么是public,要么是默认修饰符。实现接口的方法必须声明成public,因为重写的方法要比被重写的方法的访问权限高(大)。

5、   如果一个类包含一个接口但是不完全实现接口定义的方法,那么该类必须定义成abstract型。

6、   一个接口可以继承多个接口,一个类可以实现多个接口,接口之间用分隔。

四、 抽象类与接口之间的联系和区别:

   相同点:接口和抽象类的共同点是接口和抽象类都可以有抽象方法。

   不同点:

1、   抽象类可以创建对象,而接口不能创建对象,接口中的变量都是公有(public)的静态(static)的常量(final)

2、   抽象类中可以有非抽象方法,而接口中只能有抽象方法。

3、   JAVA中类与类之间是不能多继承的,而接口则没有这方面的限制。

五、JAVA中的多态。所谓多态其实就是一中物质多种形态。JAVA中常见的多态有三种表现形式:1、方法的覆盖;2、父类的引用指向子类对象;3、接口引用指向实现该接口的对象。

 

 

一、 异常捕获有两个好处:1、允许你修正错误;2、防止程序自动终止。构造catch字句的目的是解决异常情况并且向没有发生异常一样继续运行。

二、 不能单独使用try,必须与catchfinally配对出现。finally块无论有没有异常引发都会执行,finally字句是可选项,可有可无。单try或是catch块中遇到return时,要先执行finally才回来执行return语句,finally块以后的代码则不再执行。

三、 throw 抛出异常,程序执行在throw语句之后立即停止,后面的任何语句不被执行。

四、 throws 申明可能抛出的异常列表,跟在一个方法的后面,如果调用有throws字句申明的方法,必须try…catch加以限制或把该方法也使用throws字句事先申明这些异常。

五、 创建自己的异常类只要继承Exception类就可以了。

六、 父类没有捕获的异常子类也不能捕获。

 

 

一、 文件File

生成File对象的构造方法

File(String pate);

File(String path,String filename);

File(File file,String filename);

习惯使用File(String path)来创建文件对象,将文件的路径和文件名写成一个字符串来直接创建。其中字符串如果以“/”开头表示的是从该java程序所在盘符的根目录,如F:/WorkSpace/Lesson11/src/Test_readToWrite.java 这个时候如果使用File(“/test.txt”),意思就是在F盘根目录下的test.tst文件。

File对象的一些常用方法:

File.separator();   //获取该系统下的文件分隔符

File.pathSeparator(); //获取的是路径分隔符

getName();   //获取文件名

getParent();   //返回父目录名称

getPath();    //返回相对路径

getAbsolutePath();  //返回绝对路径

getParentFile();     // 返回该程序类所在位置的父目录,如果该类是在包中,则返回的是顶级包所在目录的父目录。

exits()    // 文件存在的情况下返回true 否则返回false

isFile()   // 该对象如果是文件则返回true 是目录则返回false

isAbsolute()  //文件在拥有绝对路径时返回true 否则返回false

isDirector()   //该对象是目录返回true 否则返回false

renameTo(File newname);//newname指定的文件名变成了所掉用的File对象的新的名称。

delete();//删除文件,同样可以在目录为空时删除目录。

isHidden();  判断文件是否为隐藏文件

setLastModified(long millisec) // 设置最后一次的修改时间

setReadOnly();  //设置文件为只读

二、目录:

String[] list() // 返回该文件对象下的所有文件列表,该列表示字符串数组

String[] list(FilenameFilter  FFObj) 

该形式中FilenameFilter是接口,该接口仅定义了一个方法

accept(File  directoryString  filename),该方法被文件列表中的每一个文件调用一次。FFObj 是一个实现了接口FilenameFilter 的类的引用。1

File[] listFiles()  // 返回所有的文件的对象

File[] listFiles(FilenameFilter  FFObj) // 使用方法与list的第二种用法一样

File[] listFiles(FileFilter Fobj) // 返回满足指定FileFilter的路径名的文件,FileFilter只定义了一个boolean  accept(File path)方法,将满足赛选条件的文件以对象形式返回于listFiles对象数组中。

File类的方法:

boolean mkdir() // 创建文件,失败原因包括文件已经存在或是指定的目录不存在。

boolean mkdirs() // 当创建目录不存在时,使用该方法可以创建目录以及该目录所有的父目录。

三、流的分类:

1、字节流和字符流。字节流(Stream结尾的)用来字节的输入输出,常用来读写二进制文件,如doc、图片等文件,也可用于读写文本文件,如txt文件;字符流(ReaderWriter结尾的)为字符的输入输出处理提供了方便,它采用了统一的编码标准,因而可以国际化,其次,字符流比字节流更有效率。

2、根据方向分为输入流和输出流。输入输出以程序作为参照物,向程序中输入数据叫输入流;程序向外抛出数据叫输出流。

3、节点流和处理流。直接读写数据源的流叫节点流;连接在已经存在的流的基础上的流叫处理流。

 

四、对象序列化,所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象。Java序列化很简单,实现Serializable接口的类对象可以转换成字节流或是从字节流恢复,不需要在类中增加任何代码。Serializable是标志性接口,不具有任何方法。涉及线程的类和特定JVM有非常复杂关系的类使不能序列化的。具体用途:当使用ObjectInputStreamObjectOutputStream中的writeObject readObject时,如果不实现Serializable接口,编译不会出错,执行的时候会抛出NotSerializableException异常,即使捕获异常也会在后面抛出异常,所以这个时候即必须实现Serializable接口。Serializable使用实例3

五、转换流的使用:

public InputStreamReader(InputStream in)
public OutputStreamWriter(OutputStream out)
   在字节流上加上此方法转换之后就可以用字符流的方式来读取文件了,可以再套上BufferedWriterBufferedReader,即可使用readLine()write(String str)来进行读取一行或是写入一个字符串了。

 

 

一、 集合类型:setlistmap。集合类存放的都是对象的引用,而非对象本身。

set 中的数据对象没有顺序不可以重复;

list 中的数据对象有顺序可以重复;

map 定义了存储-对的方法,键唯一

二、效率比较:Array读快改慢;Linked读慢改快;Hash基于两者之间。

三、为什么要使用集合类:数组是有固定长度的,在定义数组的时候就需要确定这个数组的内存空间,使用集合类则不需要,它会自动分配空间,自动增长。如Vector类基础内存空间是10,增长是成倍增长。集合类容纳的对象都是Object类的实例。如果是简单数据,需要把简单数据类型变成该类型类的对象,让后放入集合中处理,但这样会降低执行效率。

在集合中的对象必须是同类,否则程序执行时将抛出异常,不过便不影响程序的编译。

五、 List接口,List是有序的Collection,使用此接口能够精确的控制每个元素插入的位置,可以使用索引来访问List中的元素。实现List接口常用的类有VectorStackArrayListLinkedList

1List 方法:

void add(Object element);

int size(); //返回对象的个数

void clear();

boolean contains(Object element);//是否包含参数对象

boolean remove(Object element);

2Vector类常用方法:

void add(int index, Object element);

Object get(int index);

void removeElementAt(int index);

int catacity(); //返回当前Vector的容量

Object set(int index,Object emnt);
//用指定的元素替换此向量中指定位置处的元素,返回被替换的元素。

Vector实现了线程同步。

3Stack类是Vector的子类,常用方法:

Object push(Object item);

Object pop();

Object peek();//查看栈顶对象而不移除它

boolean empty();//判断是否为空

int search(Object o);  // 对象到栈顶的位置,以 1为基数;返回值 -1 表示此对象不在堆栈中。

4、   ArrayList类实现了可变大小的数组,它允许所有元素,包括nullArrayList不能实现线程同步。sizeisEmptygetset方法运行时间为常数,但是add方法开销为分摊的常数,添加n个元素需要O(n)的时间。其他的方法运行时间为线性。容量capacity1.5倍增长。LinkedListArrayList一样,也是非同步的。

六、Map类型的集合

1Haehtable 类 线程同步,任何非null对象都可以作为key或是value

int size();

boolean isEmpty();

get(key) 返回与键对应的值

remove(key) 删除键值对

keys();产生对键的一个枚举

elements(); 返回对所有值的一个枚举

Object put(key , value); 添加一个键值对,如果key已经存在,将用value替换旧的value,返回被替换的键值对。

2HashMap类非线程同步,允许null,即null keynull value

七、当对自己定义的类进行remove操作时,需要重写自己类的equals方法和hashCode方法,具体细节如实例4

 

遗留问题

1、集合Map 165 中说的要重写equalhashCode方法是什么意思,什么时候需要重写?还有就是为什么一定也要重写hashCode方法。

2、对集合的实际运用还不是很了解,只能简单的在作业中使用。

解决措施

第一个问题希望老师能帮助解决一下,第二个问题需要自己多敲代码

本周收获

前九章学习了java的理论基础,本周进一步学习了java的一些高级的类在代码中的具体实现细节,像文件数据的处理,集合类的各种运用,让我能在理论基础的基础上做出一点点小成果,敲代码最高兴的莫过于经过自己的努力最终出来成果,也让我体会到了理论基础是不可缺少的,但是对于理论的东西以前都是背过来的,现在我认识到只有真正的理解了才能在真正使用的时候想到怎么用它的办法。

实例1String[]  list(FilenameFilter  FFObj)的使用,在程序所在盘符的根目录下存在文件夹java,只打印显示该目录下的所有txt文件。

import java.io.File;

import java.io.FilenameFilter;

// OnlyExt 实现接口FilenameFilter,实现accept()方法

class OnlyExt implements FilenameFilter

{

         String ext;

         OnlyExt(String ext)

         {

                   this.ext = "."+ext;

         }

//dir - 被找到的文件所在的目录。

//name - 文件的名称。

         public boolean accept(File dir, String name)

         {

                   return name.endsWith(ext);

         }

}

 

public class Test_128

{

         public static void main(String[] args)

         {       // “/”表示的是该程序所在盘符的根目录

                   String dirname = "/java";

                   File f = new File(dirname);

                   FilenameFilter only = new OnlyExt("txt");

                   //调用list()方法,传递的是FilenameFilter的引用

                   String s[] = f.list(only);

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

                   {

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

                   }

         }

}

注:当调用list(FilenameFilter  FFObj)方法放回文件列表时,每扫描一个文件会自动调用FFObj指向的对象中的accept()方法,调用的同时会将文件名和之前的文件对象作为参数传递进去,当返回true时表示正在被扫描的文件满足赛选条件,要被放入list列表中返回,否则表示不满足赛选条件,不被返回到list列表中。

 

实例3Serializable的使用实例

import java.io.*;

import java.util.*;

 

public class ObjectFileTest

{

    public static void main(String[] args)

    {

        Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);

        boss.setBonus(5000);

       

        Employee[] staff = new Employee[3];

        staff[0] = boss;

        staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 15);

        staff[2] = new Employee("Tony Tester", 40000, 1990, 1, 15);

       

        try

        {

            /**

             *使用文件输出流构造一个对象输出流

             *FileOutputStream文件输出流

             *ObjectOutputStream对象输出流

             */

            ObjectOutputStream out = new ObjectOutputStream(new

                FileOutputStream("employee.txt"));

//将对象写入文件,若Employee类不实现Serializable接口,则会在执行时//抛出NotSerializableException异常

            out.writeObject(staff);     //将对象写入"employee.dat"

            out.close();        //关闭流,请牢记

           

            /**

             *使用文件输入流构造一个对象输入流

             *FileInputStream文件输入流

             *ObjectInputStream对象输入流

             */

            ObjectInputStream in = new ObjectInputStream(new

                FileInputStream("employee.txt"));

            ///readObject()将对象从"employee.dat"中读出,需要类型转换

            Employee[] newStaff = (Employee[])in.readObject();  

            in.close();

           

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

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

        }

        catch (Exception e)

        {

            e.printStackTrace();

        }

    }

}

 

///implements Serializable接口为标注该对象是可序列化的

class Employee implements Serializable

{

    public Employee() {}

   

    public Employee(String n, double s, int year, int month, int day)

    {

        name = n;

        salary = s;

        GregorianCalendar calendar =

            new GregorianCalendar(year, month - 1, day);

        hireDay = calendar.getTime();

    }

   

    public String getName()

    {

        return name;

    }

   

    public double getSalary()

    {

        return salary;

    }

   

    public Date getHireDay()

    {

        return hireDay;

    }

   

    public void raiseSalary(double byPercent)

    {

        double raise = salary * byPercent / 100;

        salary += raise;

    }

   

    public String toString()

    {

        return getClass().getName()

            + "[name = "+ name

            + ",salary = "+ salary

            + ",hireDay = "+ hireDay

            + "]";

    }

   

    private String name;

    private double salary;

    private Date hireDay;

   

}

 

class Manager extends Employee

{

    public Manager(String n, double s, int year, int month, int day)

    {

        super(n, s, year, month, day);

        bonus = 0;

    }

   

    public double getSalary()

    {

        double baseSalary = super.getSalary();

        return baseSalary + bonus;

    }

   

    public void setBonus(double b)

    {

        bonus = b;

    }

   

    public String toString()

    {

        return super.toString()

            + "[bonus = "+ bonus

            + "]";

    }

    private double bonus;

}

 

实例4定义一个Name类,类中有属性nameduty,使用Vector来存储该类对象,并进行删除操作。

import java.util.List;

import java.util.Vector;

 

class Name

{

         String name;

         String duty;

         Name(String name,String duty)

         {

                   this.name = name;

                   this.duty = duty;

         }

        

         //重写父类Object类的equals方法

         public boolean equals(Object obj)

         {

                   //直接打印obj时,会自动去调用对应类的toString()方法或是父类的toString()方法

                   System.out.println("name"+obj);

                   //instanceof 判断传进来的obj是不是Name类或是Name的子类,如果是则返回true

                   if(obj instanceof Name)

                   {

                            Name na = (Name)obj;

                            return name.equals(na.name) && duty.equals(na.duty);

                   }

                   //如果不是Name类或是Name的子类,这把比较的任务用super交给父类的equals处理

                   return super.equals(obj);

         }

        

         //重写父类Object类的hashCode方法

         public int hashCode()

         {

                   System.out.println("name.hashCode()"+name.hashCode());

                   return name.hashCode();

         }

//直接使用该类的对象时,会自动去调用对应类的toString()方法或是父类的toString()方法

//重写父类Object类的toString方法

         public String toString()

         {

                   return name;

         }

}

public class Test_overWriteEquals

{

         public static void main(String[] args)

         {

                   List<Name> li =new Vector();

                   li.add(new Name("赵剑","学员"));

                   li.add(new Name("张三","员工"));

                   li.add(new Name("李思","经理"));

                   li.add(new Name("王武","董事长"));

                   li.add(new Name("小贝","助理"));

                   Name na;

                   for(Object o :li )

                   {

                            na = (Name)o;

                            System.out.println("姓名:"+na.name+职务:"+na.duty);

                   }

                   /*当执行remove操作的时候,会自动进入重写的equals

                   Vector的第一个开始进行比较,依次把向量中的对象作为

                   参数传递到equals方法给obj,直到equals返回true

                   才删除对应的对象,如果这里不重写equals方法,那么进入

                   的将是Object类的equals方法,Object类中的equals方法为

             public boolean equals(Object obj) {

                            return (this == obj);

                       }

                   比较的是对象的地址,而不是内容   

                   */

                   li.remove(new Name("李思","经理"));

                   System.out.println("删除操作执行之后");

                   for(Object o :li )

                   {

                            na = (Name)o;

                            System.out.println("姓名:"+na.name+职务:"+na.duty);

                   }

         }

}

两种结果:

1)、当注释Name中的equalshashCOde方法时的输出结果为:

姓名:赵剑  职务:学员

姓名:张三  职务:员工

姓名:李思  职务:经理

姓名:王武  职务:董事长

姓名:小贝  职务:助理

删除操作执行之后

姓名:赵剑  职务:学员

姓名:张三  职务:员工

姓名:李思  职务:经理

姓名:王武  职务:董事长

姓名:小贝  职务:助理

 

2)、当重写equalshashCOde方法时的输出结果为:

姓名:赵剑  职务:学员

姓名:张三  职务:员工

姓名:李思  职务:经理

姓名:王武  职务:董事长

姓名:小贝  职务:助理

name赵剑

name张三

name李思

删除操作执行之后

姓名:赵剑  职务:学员

姓名:张三  职务:员工

姓名:王武  职务:董事长

姓名:小贝  职务:助理

 

部分讲解已经放在代码注释中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值