Java 面向对象、高级特性 复习总结
- 一、面向对象基础
- 1.1 面向对象思想
- 1.2 面向对象开发,设计,特征
- 1.3 类的定义
- 1.4 成员变量和局部变量的区别
- 1.5 形式参数问题
- 1.6 匿名对象
- 二、继承和多态
- 三、抽象类和接口
- 四、异常的捕获和处理
- 五、集合框架和泛型
- 5.1 List 接口
- 5.2 List 接口的常用实现类:ArrayList 和 LinkedList
- 5.3 Set接口
- 5.4 常用实现类:HashSet
- 5.5 Iterator接口
- 5.6 使用iterator遍历集合
- 5.7 使用for遍历
- 5.7 Map 接口
- 5.7.1四种遍历Map方式:
- 5.8 使用HashMap 类动态存储数据
- 5.9 Collections类---对元素进行替换查找
- 5.10 Collections类---替换集合元素
- 六、实用类
- 6.1 枚举
- 6.2 包装类
- 6.2.1 基本类型与包装类型的:
- 6.2.2 Integer类
- 6.3 Math类
- 6.4 Random类
- 6.5 String类 StringBuffer类 StringBuilder类
- 6.6 Date
- 七、线程
一、面向对象基础
1.1 面向对象思想
l 前面我们讲过数组,当有多个数组都需要遍历时,我们可以将遍历的代码封装到方法中,需要遍历时,就调用相应的方法即可,提高代码的复用性。在对数组遍历的基础上继续增加需求,比如获取最值,数值逆序等,同样需要将这些功能封装到相应的方法中。这样继续封装会发现方法越来越多,于是就想能不能将这些方法继续进行封装呢?通过前面的讲解我们知道类是可以存放方法的,所以,我们就考虑使用类封装来这多个方法,将来再做数组的操作时,不用去找具体的方法,先找到这个类,然后使用这个类中的方法。这就是面向对象思想的编程方式。
1.2 面向对象开发,设计,特征
l 面向对象开发
• 就是不断的创建对象,使用对象,指挥对象做事情。
l 面向对象设计
• 其实就是在管理和维护对象之间的关系。
l 面向对象特征
• 封装(encapsulation)
• 继承(inheritance)
• 多态(polymorphism)
1.3 类的定义
l 现实世界的事物
• 属性 人的身高,体重等
• 行为 人可以学习,吃饭等
l Java中用class描述事物也是如此
• 成员变量就是事物的属性
• 成员方法就是事物的行为
l 定义类其实就是定义类的成员(成员变量和成员方法)
类与对象案例
l 学生类
• 如何定义
• 按照事物到类的过程一步步分析
• 如何使用
• 创建对象:
• 类名 对象名= new 类名();
• 对象名.成员变量
• 对象名.成员方法
1.4 成员变量和局部变量的区别
l 在类中的位置不同
• 成员变量:类中方法外
• 局部变量:方法内或者方法声明上
l 在内存中的位置不同
• 成员变量:堆内存
• 局部变量:栈内存
l 生命周期不同
• 成员变量随着对象的存在而存在,随着对象的消失而消失
• 局部变量随着方法的调用而存在,随着方法的调用完毕而消失
l 初始化值不同
• 成员变量有默认的初始化值
• 局部变量没有默认的初始化值,必须先定义,赋值,才能使用。
1.5 形式参数问题
l 基本类型作为形式参数
l 引用类型作为形式参数
类作为形式参数的问题
如果你看到一个方法需要的参数是一个类名,就应该知道这里实际需要的是一个具体的对象。
/*
形式参数的问题:
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变直接影响实际参数
*/
**//形式参数是基本类型**
class Demo {
public int sum(int a,int b) {
return a + b;
}
}
**//形式参数是引用类型**
class Student {
public void show() {
System.out.println("我爱学习");
}
}
class StudentDemo {
//如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
public void method(Student s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
s.show();
}
}
class ArgsTest {
public static void main(String[] args) {
//形式参数是基本类型的调用
Demo d = new Demo();
int result = d.sum(10,20);
System.out.println("result:"+result);
System.out.println("--------------");
//形式参数是引用类型的调用
//需求:我要调用StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
//创建学生对象
Student s = new Student();
sd.method(s); //把s的地址给到了这里
}
}
1.6 匿名对象
l 匿名对象:就是没有名字的对象。
• 是对象的一种简化表示形式
l 匿名对象的两种使用情况
• 对象调用方法仅仅一次的时候
• 作为实际参数传递
/*
匿名对象:就是没有名字的对象。
匿名对象的应用场景:
A:调用方法,仅仅只调用一次的时候。
注意:调用多次的时候,不适合。
那么,这种匿名调用有什么好处吗?
有,匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
B:匿名对象可以作为实际参数传递
*/
class Student {
public void show() {
System.out.println("我爱学习");
}
}
class StudentDemo {
public void method(Student s) {
s.show();
}
}
class NoNameDemo {
public static void main(String[] args) {
//带名字的调用
Student s = new Student();
s.show();
s.show();
System.out.println("--------------");
//匿名对象
//new Student();
//匿名对象调用方法
new Student().show();
new Student().show(); //这里其实是重新创建了一个新的对象
System.out.println("--------------");
//匿名对象作为实际参数传递
StudentDemo sd = new StudentDemo();
//Student ss = new Student();
//sd.method(ss); //这里的ss是一个实际参数
//匿名对象
sd.method(new Student());
//在来一个
new StudentDemo().method(new Student());
}
}
二、继承和多态
三、抽象类和接口
四、异常的捕获和处理
五、集合框架和泛型
5.1 List 接口
List 接口继承自Collection接口,是有序集合
5.2 List 接口的常用实现类:ArrayList 和 LinkedList
ArrayList: 底层是可变数组 遍历元素更快,改变元素也更快
LinkedList:底层是双向链表 删除 查找更快
代码为:List a = new ArrayList();
获取集合中元素:NewTitle fist = (NewTitle)newsTitleList.getFirst();
[类名][ 元素名] = [(类名)][集合对象名,getFirst()]
5.3 Set接口
set接口 存储对象唯一、无序
5.4 常用实现类:HashSet
特点:元素是无序的、是非线程安全的 允许集合元素为null
Java中,list是可以重复的,但是set就不能重复了。
在Java中,list成为列表,而set则是集合,集合中的元素是不可以重复的,但是列表中的是可以的,所以,list里面的元素是可以重复的。
5.5 Iterator接口
iterator集合专门实现集合的遍历
hasNext() 判断是否存在下一个可访问的元素
next() :返回要访问的下一个元素
5.6 使用iterator遍历集合
Iterator it = list.Iterator;
while(it.hasNext()){
String name = (String)it.next();
}
}
5.7 使用for遍历
for(Object obj:newTiltleList){
NewTilte name = (NewTilte)obj;
sout(name);
}
5.7 Map 接口
Map接口存储一对键值对,提供key到value的映射
5.7.1四种遍历Map方式:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("1", "value1");
map.put("2", "value2");
map.put("3", "value3");
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for (String key : map.keySet()) {
System.out.println("key= "+ key + " and value= " + map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
//第四种
System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
5.8 使用HashMap 类动态存储数据
Student student1 = new Student("李明“,”男“);
Map students = new HashMap();
students.put(“Jack”,student1);
5.9 Collections类—对元素进行替换查找
Collections是对集合元素的排序。
要实现这个Collections类就要用到Comparable接口。
自然比较方法:comparaTo(),用于比较此对象与指定对象的顺序。语法:int comparaTo(Object obj)
静态方法:sort() 和 binarySearch()。语法:Collection.sort(list)
5.10 Collections类—替换集合元素
静态方法:fill()
六、实用类
6.1 枚举
- 什么是枚举?
我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了! - 定义枚举类型
定义枚举类型需要使用enum关键字,例如:
public enum Direction {
FRONT, BEHIND, LEFT, RIGHT;
}
Direction d = Direction.FRONT;
注意,定义枚举类的关键字是enum,而不是Enum,所有关键字都是小写的!
其中FRONT、BEHIND、LEFT、RIGHT都是枚举项,它们都是本类的实例,本类一共就只有四个实例对象。
在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号!建议不要省略分号!
不能使用new来创建枚举类的对象,因为枚举类中的实例就是类中的枚举项,所以在类外只能使用类名.枚举项。
6.2 包装类
6.2.1 基本类型与包装类型的:
在Java是面向对象编程,但八大基本类型却不是对象。所以八大基本类型都有对应的包装类型。
J2SE5.0后提供了自动装箱与拆箱的功能,所以需要通过包装类来转换。比如:我们可以把int型包装成Integer 类的对象。
为什么要提供包装类呢?
答:是为了在各种类型间转化,通过各种方法的调用。否则你无法直接通过变量转化。
6.2.2 Integer类
1.装箱和拆箱
装箱:将基本数据类型变为包装类对象。
拆箱:将包装类中包装的基本数据类型取出。
2.int到nteger类:
三种方法:
(1)使用Integer类的构造方法
(2)使用Integer类内部的valueOf( )方法
(3)自动装箱
(1)方法1:使用Integer类的构造方法
public Integer(int value):将int类型转换为Integer类。
public Integer(String s):将String类型转换为Integer类。
注意:使用此构造方法时,字符串内的字符必须由数字组成,不可以是字母或者其他形式,否则抛出NumberFormatException。
public static void main(String[] args)
{
//方式1:public Integer(int value)
int i= 100;
//将int类型的i转换为Integer类型的ii
Integer ii = new Integer(i);
System.out.println("ii:"+ii);
//方式2:public Integer(String s)
String s = "100";
//String s = "abc";出错,因为这个字符串必须由数字字符组成。
Integer iii = new Integer(s);
System.out.println("iii:"+iii);//100
}
(2)方法2:使用Integer类内部的valueOf方法
public static Integer valueOf(int i):将int类型转换为Integer类。
Integer i3 = Integer.valueOf(30);
(3)方法3:自动装箱的方法:
事实上,编译器自动执行了valueOf方法。
Integer ii = 100;//编译器自动执行了Integer ii = Integer.valueOf(100)
3.Integer类到 int:
(1)调用包装类的intValue()方法
(2)通过自动拆箱:
方法1:调用包装类的intValue()方法
public int intValue():以 int 类型返回该 Integer 的值。
public void test2() {
Integer i1 = new Integer(14);
Float f1 = new Float(12.3F);
//1.调用包装类的XxxValue()方法
int i2 = i1.intValue();//i2 = 14
float f2 = f1.floatValue();//f2 = 12.3
}
方法2:通过自动拆箱:
编译器自动执行了valueOf方法
//5是基本数据类型,通过自动装箱变成对象类型。
//编译器执行了Integer iii = Integer.valueOf(5)
Integer iii=5;
//自动拆箱,实际上执行了 int iii2 = iii.intValue()
int iii2=iii;
System.out.println(iii2);
6.3 Math类
public class TestMath {
public static void main(String[] args) {
// Math.random();
// Math.ceil(12.2);//向上取整
//
// Math.round(1.2);
// System.out.println(Math.round(1.49905+0.00195));
// System.out.println();
// double e = Math.E;
}
}
6.4 Random类
在JDK的java.util包中有一个Random类,他可以在指定的取值范围内随机产生数字。在Random类中有两种构造方法
Random() 无参构造方法,用于创建一个伪随机数生成器。
Random(long seed) 有参构造方法,使用一个long类型的seed种子创建伪随机数生成器。
首先演示无参构造方法,每次产生的随机数不同
代码为例:
import java.util.Random;
public class Main{
public static void main(String[] args)throws Exception{
Random r=new Random(); //不传入种子
for(int i=0;i<8;i++){
System.out.println(r.nextInt(100));
}
}
再演示有参构造方法,每次产生的随机数相同
import java.util.Random;
public class Main{
public static void main(String[] args)throws Exception{
Random r=new Random(100); //传入种子
for(int i=0;i<8;i++){
System.out.println(r.nextInt(100));
}
}
}
6.5 String类 StringBuffer类 StringBuilder类
一、Java String 类——String字符串常量
简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,这样不仅效率低下,而且大量浪费有限的内存空间,所以经常改变内容的字符串最好不要用 String 。因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。
二、StringBuffer 和 StringBuilder 类——StringBuffer、StringBuilder字符串变量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安
当对字符串进行修改的时候,特别是字符串对象经常改变的情况下,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
6.6 Date
七、线程
一、线程实现方式
线程实现有两种方式:继承Thread类,实现Runnable接口
1、继承Thread类
Java代码 收藏代码
public class MyThread extends Thread{
@Override
public void run() {
System.out.println("Mythread执行");
}
}
Java代码 收藏代码
public class TestMain {
public static void main(String[] args) {
MyThread mythread = new MyThread();
mythread.start();
}
}
要点:继承Thread类,重写run方法,在run方法内编写代码实现业务。通过Thread实例的start方法启动多线程。
2、实现Runnable接口
Java代码
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("MyRunnable执行");
}
}
Java代码
public class TestMain {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
要点:实现Runnable接口,实现run方法,在run方法内编写代码实现业务。通过Thread(new Runnable实现类)构造函数,构造Thread,通过Thread实例的start方法启动多线程。
二、Thread 和 Runnable 的不同点
Runnable是接口;
Thread 是类,Thread本身是实现了Runnable接口的类;
我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。
此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
通常,建议通过“Runnable”实现多线程!