集合框架(四) 一、集合框架工具类 1.Collections工具类1)定义Collections工具类用于对集合进行各种操作。 2)常用方法1> 排序操作 格式:static void sort(List list):自然排序static void sort(List list, Comparator c):自定义排序 示例代码: 程序输出结果: [z, qq, zz, aaa, abcd, kkkkk] 2> 获取最大元素 格式:static max(Collection coll): 根据元素的自然顺序,返回指定collection中的最大元素static T max(Collection coll, Comparator comp):获取指定排序下的最大元素 示例代码(以上述代码为例): Collections.max(list);程序输出结果:zz Collections.max(list, new StrLenComp());程序输出结果:kkkkk 3> 二分搜索 格式:static int binarySearch(List<? extends Comparable<? super T>> list, T key):搜索指定元素static int binarySearch(List<? extends T> list,…
Tag: Java
Java基础—集合框架(三)
集合框架(三) 一、Map集合 1.概述Map集合用于存储键值对,且它保证键的唯一性,并且每个键最多只能映射一个值。Map集合是Set集合的底层实现,其和Collection在集合框架中并列存在。 2.Map集合共性方法1)添加操作 -V put(K key, V value):添加指定的键值对-void putAll(Map<? extends K, ? extends V>, m):添加指定Map集合 注意:put()会返回该键对应的被覆盖的值第一次存储put(“01”, “zhangsan”);返回null;”01″键对应的被覆盖的值为null;第二次存储put(“01”, “wangwu”);返回”zhangsan”;”01″键对应的被覆盖的值为”zhangsan”; 2)删除操作 -void clear():清楚所有映射关系-V remove(Object key):根据键删除映射值 3)判断操作 -boolean containsKey(Object key):判断是否包含指定键的映射关系-boolean containsValue(Object value):判断是否包含指定值的映射关系-boolean isEmpty():判断是否为空 4)获取操作 -V get(Object Key):通过键获得值-int size():获取Map长度-Collection values():返回所有的映射的值-Set entrySet():返回包含的映射关系-Set keySet():返回包含的键 3.Map集合子类 Map HashTable HashMap TreeMap 1)HashTableHashTable底层是哈希表数据结构。此类实现一个哈希表,该哈希表将键映射到相应的值上。任何非null的对象都可以做键或值。为了成功在哈希表中存储和获取对象,用作键的对象必须实现hashCode()方法和equals()方法。HashTable类是线程同步的。 2)HashMapHashMap底层是哈希表数据结构。此类与HashTable大致相同,但允许使用null的对象作为键或值。HashMap不保证映射的顺序,特别是它不保证该顺序恒久不变。HashMap类是线程不同步的,效率高于HashTable。 3)TreeMapTreeMap底层是二叉树数据结构。此类可以实现为Map集合中的键排序。TreeMap线程不同步。 4.Map集合方法应用演示Map集合基本方法。 示例代码: 程序输出结果: 5.Map集合元素取出方式1)keySet()方法将Map中所有的key存入Set集合,再通过Set集合的迭代器将所有key取出,最后通过get()方法获取每个key的对应值。 示例代码: 程序输出结果: 2)entrySet()方法将Map集合中的映射关系存入到Set集合中。该关系的数据类型是Map.Entry。 示例代码:…
Java基础—集合框架(二)
集合框架(二) 一、TreeSet 1.TreeSet集合特点可以对Set集合中的元素进行自然排序。往TreeSet里面的对象,必须具有比较性,才可以实现排序。 2.TreeSet集合排序实现方式1)元素实现Comparable接口要获得元素的比较性,需要进行存储的对象可以实现Comparable接口,并复写compareTo()方法,自定义比较方式;这是通过让元素获得比较性的方法,完成TreeSet排序功能。 2)集合初始化Comparator当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时可以让集合调用具备比较功能的构造方法,将比较器对象作为参数传给TreeSet集合的构造方法;这是让集合自身具备比较功能,完成TreeSet排序。 注意:-TreeSet集合保证元素唯一新的依据是comparteTo()方法的返回值为0;-当元素和集合都具备比较功能时,以集合的比较器为主 3.TreeSet集合运用1)继承Comparable接口的方法实现元素的可比性使用TreeSet集合存储自定义对象。 示例代码: 程序输出结果: 注意:排序时,当主要条件相同时,一定要判断次要条件 2)调用TreeSet具备比较器构造方法 示例代码: 程序输出结果: 4.二叉树数据结构1)定义 二叉树数据结构的原则是将小的元素依次放在左边,大的元素依次放在右边。在取数据时,二叉树从最小的元素开始,依次往上取到最大值。这样的数据结构,可以减少比较次数,提高运行效率。 2)二叉树运用使用二叉树原理实现数据存储和取出顺序一致。 示例代码: 要使存储和取出的顺序一致,只需在复写的compareTo()方法中,return 1;即可;存储与取出成倒序,只需return -1;即可 5.TreeSet练习1)按照字符串的长度排序 示例代码: 程序输出结果: 二、泛型 1.概述 由一个小例子引出泛型: 如果没有泛型的支持,后添加的整型数据4,在运行时会出现运行时期类型转换异常,int类型无法被转换为String类型,但是这个异常在编译时期,没有任何提示。为了避免这样的情况,需要程序在编译时期就给出异常,以便开发者解决问题,Java引入了泛型机制。 JDK5.0版本之后的新特性,用于解决集合存储的安全问题。 泛型格式(以储存String类型数据为例): ArrayList<String> arrayList = new ArrayList(); 声明一个ArrayList容器,存储String类型的元素。这样,上述程序在编译时期就会报出异常。容器声明加上了泛型,那么迭代器的声明也应加上泛型: Iterator<String> it = arrayList.iterator(); 2.泛型的优点1)将运行时期出现的ClassCastException转移到编译时期,方便开发者解决问题,更安全;2)避免了迭代时期类型强制转换的麻烦;3)泛型类的出现优化了程序设计 3.泛型的应用当在声明容器的时候指定了泛型,后期实现Comparator接口和Comparable接口的时候,可以指定Comparator接口的泛型;这样做,避免了比较时的类型转换。 Comparator接口泛型示例代码: Comparable接口泛型示例代码: 注意:复写equals()方法的时候,传的参数必须是Object obj;因为Object类没有泛型 4.泛型类1)定义泛型类是在一个类要操作对象,而对象类型又不明确时出现的。 2)泛型类格式声明泛型类,只需要在类名后加上<T>即可:class GenericClass<T> 3)泛型类应用当一个类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型来完成扩展。例如,当一个工具类中要操作不同的对象Worker和Student时,早期通过接收Object对象,然后通过类型转换类完成操作;现在只需定义泛型,无需类型转换。 早期实现: 如果现在要操作的是Worker对象,而在setObject()方法中误传入了Student对象,编译不会报错,但是运行时会出现类型转换异常。 泛型实现: 如果现在要操作的是Worker对象,而在setObject()方法中误传入了Student对象,编译无法通过;并且泛型实现无须进行类型转换,既简化了代码,又提升了安全性。5.泛型方法1)定义泛型类在使用的过程中有其局限性。例如一个泛型类被定义了只能操作String类型的对象,那么该类中需要接收参数的方法,都只能操作String对象;此时如果给该类中的方法传递了非String类型数据,编译就会出错。为了程序更加灵活,现在想实现一个类中不同的方法操作不同类型的对象,而要操作的对象不能确定,那么就可以使用泛型方法。 2)泛型方法格式要声明泛型方法,只需在方法修饰符后面,返回值的前面加上<T>即可:private <T>…
Java基础—集合框架(一)
集合框架(一) 一、概述 1.集合出现的原因Java中,数据被封装成对象;对象完成了对数据的存储。而集合的出现,完成了对对象的存储,方便对对象进行操作。 2.集合与数组的区别1)数组虽然可以存储对象,但是长度固定,不利于后期扩展;只能存储同一类型对象;2)集合的长度是可变的;并且能存储不同类型对象 3.集合的特点1)长度可变;2)可以存储不同类型的对象;3)集合只用于存储对象,不能存储基本数据类型 二、Collection 1.定义Collection是集合框架层次结构中的根接口。Collection提供了具体的自接口(如Set和List)实现。这个根接口用来传递collection,并提供共性方法,操作这些collection。 2.共性方法1)添加操作 -boolean add(E e):添加指定元素到集合中-boolean addAll(Collection<? extends E> c):添加指定集合中的所有元素到当前集合中 2)判断操作 -boolean contains(Object o):判断当前集合中是否包含指定元素-booean isEmpty():判断当前集合是否为空 3)删除操作 -void clear():清空当前集合-boolean remove(Object o):移除指定元素-boolean removeAll(Collection<?> c):指定一个集合,将该集合中的元素从当前集合中移除 4)获取操作 -int size():获取当前集合长度-booean retianAll(Collection<?> c):取当前集合与指定集合的交集-Iterator iterator():迭代器,用于取出集合中元素 3.共性方法演示演示Collection中的共性方法。 示例代码: 注意:-add()方法的参数类型是Object,以便于接受任意类型对象;-集合中存放的不是对象实体,存储的是对象内存地址 三、迭代器 1.定义迭代器是对Iterator接口的实现,用于取出集合中的对象,以便于对对象进行操作。 容器的取出操作,不足以用一个方法描述。每个容器的取出操作过程,都有所不同。因此,容器将取出操作封装成一个对象,对象中提供了多个功能以实现容器对象的取出操作。 每个容器类的内部,都定义了做取出操作的内部类(便于直接访问容器内部的元素),用于取出各容器不同数据结构中的对象。这个取出操作被称为迭代器。无论是什么容器,其迭代器的操作都会有判断和取出的操作,将这些操作提取之后形成了Iterator接口。每个容器通过调用iterator()方法,获得自身的迭代器。 2.迭代器的使用iterator()方法返回的是一个Iterator接口的子类对象1)获取iterator迭代器:Iterator it = arraylist.iterator();2)调用next()方法获取第一个元素并打印:System.out.println(it.next());3)调用hasNext()方法,循环取出所有元素 四、List 1.List集合的特点List集合中的元素是有序的,并可以重复。该集合体系有索引。 2.List集合特有方法凡是操作索引的方法都是该体系特有的方法。1)添加操作 -void add(int index, E element):添加指定元素-boolean addAll(int index, Collection<?…
Java基础—String类
一、String类 1.概述1)字符串解读String s1 = “abc”; s1是一个类类型变量,”abc”是一个对象。只要在””里的,都是对象。字符串最大的特点在于,一旦初始化,就不可以改变。字符串,既是对象,又是常量。 示例:String s1 = “abc”;s1 = “kk”;System.out.println(s1); 输出结果为:kk变化的不是”abc”这个对象,而是s1这个引用;重新赋值后,s1指向了”kk”这个对象。 2)字符串创建方式的区别 高能:String s1 = new “abc”;String s2 = new String(“abc”);s1和s2的区别在于,s1有一个对象,s2有两个对象。s2中,new是一个对象,”abc”是一个对象。 小扩展字符串在内存中有常量池,该常量池是一个数组,用于存储’a’,’b’,’c’这样的字符;字符串由字符组成,如果常量池中有’a’,’b’,’c’,’d’,’e’,’f’这些字符,下次创建String s3 = “abf”;的时候,虚拟机会到常量池中找到这三个字符,拼接起来。 3)String类的equals()方法String类复写了Object类中的equals()方法,该方法用于判断字符串是否相同。 示例:String s1 = new “abc”;String s2 = new String(“abc”);System.out.println(s1.equals(s2)); 输出:true 4)String的“==”操作符比较 示例代码: 输出结果为: 字符串储存在常量池当中,当s1创建的时候,”abc”对象已经在内存中存在了;那么,当s3创建的时候,如果常量池中已经有”abc”字符串的字符,就不会再创建对象,而直接让s3指向”abc”这个对象。2.String类中的方法String类是用于描述字符串这个事物。其常见的方法有:1)获取操作1> 获取字符串长度:int length()2> 获取指定位置上的字符:char charAt(int index)3> 获取指定字符的位置有如下方法: a.int indexOf(int ch):获取指定字符第一次出现的位置b.int indexOf(int ch, int fromIndex):获取指定字符从fromIndex位置开始,第一次出现的位置c.int…
Java基础—多线程(二)
多线程(二) 一、线程间通信 1.定义线程间通信就是多个线程操作同一资源,但是操作的动作不同。 2.等待唤醒机制等待唤醒机制,是由wait(),notify()或notifyAll()等方法组成。对于有些资源的操作,需要一个线程完成一步,进入等待状态,将CPU执行权交由另一个线程,让它完成下一步的操作,如此交替进行。这个过程中,一个线程需要在完成一步操作后,先通知(notify())另一个线程运行,再等待(wait()),进入冻结状态,以此类推。等待中的线程,都储存在系统线程池中,等待这被notify()唤醒。 以下代码,通过等待唤醒机制,实现了生产一个披萨,消费一个披萨: 程序运行部分结果如下: 3.Object类中的wait等方法wait()等多线程同步等待唤醒机制中的方法,被定义在Object类中是因为:首先,在等待唤醒机制中,无论是等待操作,还是唤醒操作,都必须标识出等待的这个线程和被唤醒的这个线程锁持有的锁;表现为代码是:锁.wait();锁.notify();而这个锁,由synchronized关键字格式可知,可以是任意对象;那么,可以被任意对象调用的方法,一定是定义在了Object类当中。wait(),notify(),notifyAll()这些方法都被定义在了Object类中,因为这些方法是要使用在多线程同步的等待唤醒机制当中,必须具备能被任意对象调用的特性。所以,这些方法要被定义在Object类中。 4、生产者消费者模型在实际生产时,会有多个线程负责生产,多个线程负责消费;那么在上述代码中启动新线程,来模拟多线程生产消费的情况。 示例代码: 用这样的方式,运行会出现如下结果: 生产了两个披萨,但只消费了一个。现在0,1线程负责生产,2,3线程负责消费,原因推断:1)当0线程生产完一个披萨,进入冻结;2)1线程判断有披萨,进入冻结;3)2线程消费一个披萨,唤醒0线程,进入冻结;4)3线程判断没披萨,进入冻结;5)现在出于运行状态的只有0线程,0线程生产一个披萨,唤醒1线程(1线程是线程池中第一个线程),进入冻结;6)1线程又生产了一个披萨 这导致了生产两个,只消费一个的问题。这个问题的发生是因为,第5步0线程唤醒1线程的时候,由于1线程的等待代码在if语句中,1线程醒了之后,不需要再判断flag的值所导致。如果1线程被唤醒,还要继续判断flag的值,就不会产生这个情况。因此,要将if判断,改为while循环,让线程被唤醒之后,再次判断flag的值。 示例代码: 每次被唤醒,都要判断flag的值。代码运行结果如下: 程序出现了无响应,因为使用while循环,可能会出现所有线程全部进入冻结状态的情况。要解决这个问题,必须用到另一个方法notifyAll();唤醒所有线程。由于用了while循环,所有线程被唤醒之后第一件事是判断flag的值,所以不会再出现多生产或多消费问题。至此,程序运行正常。 示例代码: 程序运行部分结果: 二、jdk5新特性 1.概述jdk5开始,提供了多线程同步的升级解决方案。将synchronized关键字,替换成Lock接口;将Object对象,替换为Condition对象;将wai(),notify(),notifyAll()方法,替换为await(),signal(),signalAll()方法。一个锁,可以对应多个Condition对象。这个特性的出现,可以让多线程在唤醒其他线程时,不必唤醒本方的线程,只唤醒对方线程。例如在生产者消费者模型中,使用Lock和Condition类,可以实现只唤醒消费者线程,或只唤醒生产者线程。 2.Lock接口和Condition接口1)Lock接口已知实现类中,有ReentrantLock类。这个子类可以用来实例化,创建ReentrantLock对象 ReentrantLock lock = new ReentrantLock(); 2)Condition接口的实例可以通过newCondition()方法获得 Condition conditon = Lock.newCondition(); 3)一个Lock对象可以对应多个Condition对象 Condition condition1 = Lock.newCondition();Condition condition2 = Lock.newCondition(); 3.新特性应用将此新特性应用在消费者生产者模型中,实现只唤醒对方线程。 修改之后的Pizza类代码如下: 分别创建的conditionPro和conditionCon对象,用于实现只唤醒对方线程,代码更优。 三、停止线程 1.线程停止原理stop()方法已经过时,停止的唯一标准就是run()方法结束。开启多线程运行,运行代码通常都是循环结构,只要控制住循环,就可以让run()方法结束,就可以让线程结束。 注意:当线程处于冻结状态,无法读取控制循环的标记,线程就不会结束。 2.interrupt()方法将处于冻结状态的线程,强制恢复到运行状态。interrupt()方法是在清除线程的冻结状态。 示例代码: 如果不调用t1和t2线程的interrupt()方法,程序会无响应,因为两个线程都处于冻结状态,无法继续运行。 上述程序运行结果: 四、Thread类其他方法 1.setDaemon()方法将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java虚拟机退出。该方法必须在启动线程前调用。守护线程可以理解为后台线程。后台线程开启后,会和前台线程(一般线程)一起抢夺CPU资源;当所有前台线程结束运行后,后台线程自动结束。可以理解为,后台线程依赖前台线程的运行。 示例代码: 在启动两个线程前,将两个线程设置为守护线程,其他代码不变;那么这两个线程依赖主线程运行;虽然这两个线程都处于冻结状态,但是当主线程运行完毕,这两个守护进程随之结束。 2.join()方法调用join()方法的线程,在申请CPU执行权。之前拥有CPU执行权的线程,将转入冻结状态,等调用join()方法的线程执行完毕,再转回运行状态。 示例代码: 程序在启动t1线程之后,主线程先等待t1线程打印完100个数;主线程再继续和t2线程交替打印100个数。…
Java基础—多线程(一)
多线程(一) 一、进程和线程 1.区别和联系区别:进程是一个正在进行中的程序。每一个进程执行都有一个执行顺序,该顺序是一个执行路径,或一个控制单元。进程是系统进行资源分配和调度的一个独立单位。每一个应用程序启动的时候,都会被分配一定的内存空间。进程是用于标识这片内存空间,用于封装内存空间里的控制单元。 线程是进程中一个独立的控制单元,控制着进程的执行。它是CPU分配和调度其资源的基本单位。线程没有办法脱离进程独立运行,必须包含在进程中运行。多线程之间共享进程拥有的资源。 联系:进程和线程都是系统创建的。一个进程中至少有一个线程。同一个进程中的多个线程可以并发执行,提高程序运行效率。 示例代码: 用dos命令行编译上述代码时,会启动javac进程;运行上述代码时,会启动java进程,该进程中至少有一个线程在负责java程序的执行,而且这个线程运行的代码存在于main方法中,该线程称为主线程。 小扩展jvm启动的时候,不止一个线程,还有负责垃圾回收机制的进程。 二、多线程 1.多线程存在的意义多线程的出现能让程序产生同时运行的效果。 2.自定义线程Java提供了对线程这类事物的描述,封装为Thread类。创建线程有两种方式:1)继承Thread类,复写run()方法,调用线程的start()方法 示例代码: start()方法启动线程,调用run()方法;修改代码,分析打印结果。 示例代码: 程序运行部分结果: 运行结果每次都不同,因为多个线程都在获取CPU的执行权(资源);CPU执行哪个线程,就运行哪个线程里的代码;某一时刻,只有一个线程在运行(多核除外);CPU在做着快速切换,达到了看上去程序是同时运行的效果。这是多线程的随机性。如图: 程序开始运行,主线程启动,随后创建好的myThread线程启动,负责执行run()方法中的代码;主线程负责执行main()方法中的代码;CPU分配资源,交替执行两个线程,所以有如上运行结果。 小扩展1复写run()方法的原因Thread类用于描述线程,该类定义了一个功能用于存储线程要运行的代码,这个功能就是run()方法。 小扩展2直接调用子类中的run()方法,程序的运行结果示例代码: 程序运行结果为: 如果直接调用run()方法,该程序并没有启动新的线程,而整个程序是由主线程完成执行的。myThread线程虽然被创建,但是始终没有启动。如图: 主线程执行到run()方法,就将run()方法中的代码先执行完,再回到main方法中,执行main方法中的代码;主线程独享CPU资源;直接调用run()方法的效果,相当于对象调用方法,没有多线程执行的特点。 小练习1创建两个线程,和主线程交替运行。示例代码: 程序部分运行结果为: 小练习2用Thread类的getName()方法,打印线程名称示例代码: 程序部分运行结果为: Thread-0即为tt1线程名称。每个线程有自己默认的名称,即Thread-[编号]。标准通用的获取当前线程名称的方法是使用Thread类的currentThread()方法: Thread.currentThread().getName(); currentThread()方法为静态方法,获取当前线程对象,返回Thread类型。如果要自定义名称,使用Thread类的setName()方法或使用线程构造方法即可。 2)实现Runnable接口用多线程实现一个简单的多窗口卖票程序。 示例代码: 程序部分运行结果为: 上述程序声明了静态成员,由于静态成员声明周期过长,一般不建议使用静态属性。如果没有静态,则每个线程对象里有100张票,总共将卖出400张。要解决这个问题,就要使用线程的第二种创建方法:实现Runnable接口。 实现Runnable接口的步骤:1> 声明一个类,实现Runnable接口示例代码:class Ticket implements Runnable {} 2> 复写Runnable接口中的run()方法,将线程要运行的代码存放在run()方法中示例代码:class Ticket implements Runnable {public void run() {} } 3> 创建Thread线程对象,并将Runnable接口的子类对象作为实际参数传给Thread类的构造方法示例代码:Ticket ticket = new Ticket();Thread…
Java基础—面向对象(五)
面向对象(五) 一、finally关键字 1.定义finally代码块,定义了无论异常发生与否,一定会执行的代码。通常用于关闭资源。流操作,数据库操作等,最后都应该用finally关闭流和数据库连接,以确保资源释放。 2.异常处理的分层设计分层设计是模块式开发的体现,每个开发者负责相应的模块。如果异常出现,各开发者负责处理各自模块的异常,并封装好能够被其他模块开发者解决的异常对象(层内封装),抛出给相应开发者。这样的开发模式,让异常处理合理化,每个异常都能被有效解决,提高开发效率。 3.异常处理语句格式1)try catch 示例代码: 2)try catch finally 示例代码: 3)try finally 示例代码: 该格式用于,在程序其他地方处理异常,但在此try fianlly语句中一定要关闭资源的情况,将关闭资源的代码,放在finally中。 小扩展finally在其之前异常处理阶段出现了System.exit(0);这行代码的情况下,不会被执行 示例代码: 程序输出结果为: 二、异常在继承状态中的特点 1.子类在复写父类方法时,如果父类的方法抛出异常,那么子类复写的方法只能抛出父类异常或其异常的子类 示例代码: 异常结构图: Exception AException BException CException 子类继承父类,子类不能比父类出现的异常还多;其出现的异常,也只能是父类的异常,或父类异常的子类。 示例代码: 上述代码,在main方法中将SubClass的对象传给function()方法,而function()方法接受一个父类对象作为参数,即父类引用指向子类对象;那么p.method()调用的是子类SubClass的method()方法;由于父类抛出的是AException,在Test类中用try catch进行捕捉,并且catch语句只能处理AException及AException的子类;如果子类的method()方法抛出的是CException,CException和AException没有任何关系,catch语句无法处理,程序无法编译;如果子类的method()方法抛出的是AException或BException,AException是父类方法抛出的异常,BException是父类方法异常的子类,那么catch语句中捕捉AException就能处理子类方法抛出的异常;这是为什么子类复写父类的方法,只能抛出父类方法的异常,或父类方法异常的子类。 2.如果父类方法抛出多个异常,那么子类复写该方法时,只能抛出父类方法异常或其子集父类抛出A,B,C异常,子类只能抛出A,B,C异常或A,B,C异常的子集 3.如果父类或者接口的方法中没有抛出异常,子类复写的方法也不能抛出异常通用规则,如果子类方法可能会发生父类方法中没有的异常,只能在子类方法内部进行catch处理,不能抛出。 4.运行时异常练习写一个程序,获取长方形面积;如果初始化的时候传入的长或宽的值小于等于0,抛出异常。 示例代码: 创建Rectangle对象,传入0,4,程序运行结果为: 异常机制的出现,让问题处理代码和正常流程代码分离,代码阅读性更强。 三、异常机制总结 1.异常的定义异常是对问题的描述,并将问题封装成对象。 2.异常的优点1)将问题进行封装;2)将正常流程代码和问题处理代码分析 3.异常处理原则1)异常有两种处理方式:try catch或者throws;2)调用抛出异常的方法时,抛出了几个异常,就要处理几个异常;3)多个catch语句,处理异常父类的catch语句放在最下面;4)catch内,定义针对性的处理方式,不要简单打印,也不要什么都不定义;5)捕获的异常,如果处理不了,可以继续在catch中抛出;6)在抛出异常时,尽量结合分层设计思想,将异常转化为其他模块可以处理的异常,封装后再抛出 4.异常注意事项1)子类复写父类的方法时,子类复写的方法抛出的异常必须是父类方法抛出的异常或父类方法抛出异常的子类或者子集;2)如果父类或者接口的方法没有抛出异常,子类复写的方法不能抛出异常;如有异常,只能内部解决 5.异常体系 Throwable Error Exception RuntimeException 异常体系中的所有类,以及建立的对象,都具备可抛性,可以被throw和throws关键字操作。 6.throw和throws的区别1)throw定义在方法内,用于抛出异常对象方法内抛出的异常对象(非运行时异常),必须在方法上声明,或用try catch处理,否则编译失败;throw单独存在时,下面不要定义语句,因为执行不到2)throws定义在方法上,用于抛出异常类方法上声明了异常,调用这必须进行处理,可以抛出,也可以try catch 7.异常的分类1)编译时异常(编译时被检测)该异常在编译时,如果没有处理(没有抛出,也没有try catch),编译失败2)运行时异常(编译时不检测)该异常在编译时不需要声明或者处理,编译都通过;该异常的发生,建议不处理,让程序停止,由方法调用者对代码进行修正 8.异常处理代码try…
Java基础—面向对象(四)
面向对象(四) 一、内部类 1.内部类的定义将一个类定义在另一个类的内部,这个内部的类就被成为内部类(内置类,嵌套类)。 2.内部类的特点1)内部类可以直接访问外部类的成员,包括私有成员(成员前省略了外部类名.this.);2)外部类要访问内部类的成员,必须建立内部类的对象,通过内部类对象访问 示例代码: 程序输出结果为: 3)当内部来在外部类的成员位置上时,可以被private关键字修饰,进行封装 示例代码: 4)外部其他类直接访问内部类成员(内部类声明在外部来成员位置上,且非私有) 示例代码: 5)不涉及特有数据的时候,内部类可以被static关键字修饰,具备静态特性 内部类被静态修饰后,只能访问外部类的静态成员,有访问局限性。外部其他类直接访问静态内部类的非静态成员的方式为: 示例代码: 外部其他类直接访问静态内部类的静态成员的方式为: 6)内部类中若声明了静态成员,该内部类必须是静态的7)外部类的静态方法访问内部类时,内部类必须是静态的8)重名变量注意事项 示例代码: 程序输出结果为: 如果要输出4,输出语句应为System.out.println(“Inner: ” + this.x);如果要输出3,输出语句应为System.out.println(“Inner: ” + Outer.this.x); 9)内部类可以被定义在局部位置上内部类定义在局部位置上的示例及特点 示例代码: 特点:1> 不可以被成员修饰符修饰,如private2> 仍持有外部类的引用,仍可以直接访问外部类的成员3> 如果要访问其所在局部的局部变量,要用final修饰该变量 3.内部类的应用描述事物的时候,如果事物内部还包含有事物。由于该内部事物在使用外部事物的内容,所以该内部的事物用内部类来描述。如描述人体的时候,人体由器官组成,包括心脏;心脏有属性(成员变量),行为(成员方法),比较复杂(应声明成一个类),心脏又和人体其他器官有直接的联系(需要直接访问外部类的成员),那么应将心脏作为对象封装,形成人体的内部类,并私有,对外提供方法访问。 二、匿名内部类 1.定义没有名字的内部类叫做匿名内部类,即内部类的简写格式 2.匿名内部类使用的前提内部类必须继承一个类或者实现接口 示例代码: 3.匿名内部类是一个匿名子类对象,是一个带内容的对象,是将定义类和创建对象封装为一体的表现方式,为了简化书写,方便方法调用而存在 匿名内部类就是一个子类继承父类的类体,除了复写父类的方法,还能在匿名内部类中定义子类的特有方法(面试用) 示例代码: 匿名内部类中的方法不要超过3个 4.匿名内部类的应用 示例代码: 5.匿名内部类练习根据main方法中的代码,补全其他代码 示例代码: 小扩展(面试用):没有实现接口,也没有继承任何父类,仍然可以使用匿名内部类调用方法;只需使用所有类的父类Object类即可示例代码: 三、异常机制 1.定义异常是程序在运行(非编译)过程中出现的不正常情况。异常用来描述生活中出现的问题,也是一个对象。 2.问题的分类Java对于问题的描述分为两大类,有严重与非严重之分。对于严重的问题,Java用Error类来描述,称为错误;对于非严重的问题,Java用Exception类进行描述,称为异常。1)对于Error,一般不编写针对性的代码进行处理;2)对于Exception,可以针对性的编写代码进行处理 Error和Exception都是Throwable的子类 3.异常的处理Java提供了特定的语句对异常进行处理: 示例代码: 示例代码: 4.异常对象常见方法1)getMessage() 示例代码: 2)toString() 示例代码:…
Java基础—面向对象(三)
面向对象(三) 一、多态 1.多态定义多态就是事物存在的多种体现形态。多态允许同一父类不同的子类对象对同一方法产生不同的行为方式。例如,中国人和俄罗斯人都是人的子类,都具备吃饭这个功能;但是当中国人和俄罗斯人分别调用吃饭这个方法的时候,其执行变现出不同的行为方式,即俄罗斯人是用叉子吃,中国人是用筷子吃。 2.多态的体现多态是指在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。示例代码一步一步解释多态的形成过程。 定义一个Man类,代表人,定义俄罗斯人Russian和中国人Chinese的类,并继承Man,复写Man中的eat()方法,并创建对象调用该方法。 示例代码: 在主函数中,如果要创建很多个Russian对象,或者Chinese对象,就要写很多句对象.方法的语句,那么将该语句提取成方法。 示例代码: 但是这么一来,如果以后还要加入印度人Indian,他们用手吃饭。那么在主函数中,就要加入新的eat()方法: public static void eat(Indian i); 如果以后还要创建很多国家人的对象,这样的方式就不合理。由于无论俄罗斯人,中国人还是印度人,都是人的子类,那么语句: Man m = new Chinese(); 是没有问题的,因为中国人是人。所以,修改之后的代码,就是多态的体现。 示例代码: 主函数中func()方法在执行的时候,判断接收到的人对象的具体类型是中国人还是俄罗斯人(动态绑定),最后调用相应对象的eat()方法,体现多态。 小扩展:Man r = new Russian();这行代码,是向上转型,将子类Russian向上转型为Man类型,也称为类型提升。 3.多态的前提要实现多态,必须有:1)继承必须有类与类之间的继承关系,有继承,才有第二前提复写; 2)复写必须有子类对父类方法的复写,有复写,多态才有可以调用的方法,存在才有意义; 3)父类引用指向子类对象(向上转型)必须有向上转型,子类都继承于父类,多态在程序执行期间,通过判断调用方法的对象的实际类型,体现出具体方法内容,才能达到让代码具备可扩展性的目的 4.多态的利弊1)利:多态提高了程序的扩展性; 2)弊:只能使用父类的引用访问父类中的成员(详细解释见代码) 示例代码: 如果想要调用Chinese对象特有的speak()方法,应该强制将父类引用向下转型成子类类型。 示例代码: 注意:Man m = new Chinese();Chinese c = (Chinese)m;这是合法的;但是如果写成:Man m = new Man();Chinese c = (Chinese)m;这是非法的,m指向的是人类型,不能说人就是中国人。转型的原则可以理解成,自始至终是子类的对象在做向上或者向下转型。 小扩展:instanceof运算符m instanceof Chinese判断m是否属于Chinese类型,是,返回true,否,返回false 5.多态使用的注意事项1)多态状态下成员方法的特点:以代码Parent…