Java 面向对象、高级特性 复习总结

一、面向对象基础

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 枚举

  1. 什么是枚举?
    我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
      我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了!
  2. 定义枚举类型
    定义枚举类型需要使用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

https://blog.csdn.net/weixin_38610651/article/details/82796317

七、线程

一、线程实现方式

线程实现有两种方式:继承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”实现多线程!

猜你喜欢

转载自blog.csdn.net/qq_42005540/article/details/113846668