一、Java基础

二、Java面向对象

一、面向对象两大元素

1.两大元素

类:即类型,在JAVA中用class表示,是对现实一类事物的抽象

对象:即某一类型事物的具体存在,在JAVA中用Object表示

2.类与对象的关系

  • 程序的目的在于解决客观世界存在的问题,我们首先需要对问题领域中存在的物质进行抽象,这样也就有了类。
  • 如解决“黄鼠狼给鸡拜年”的问题,这里客观世界中有一只黄鼠狼和一只鸡,我们抽象出来后在程序的世界中就有了两个类:黄鼠狼、鸡。客观世界中的“一只黄鼠狼”对应的就是程序世界中黄鼠狼这个类的一个实例或者说一个对象。

3.类的定义

如上黄鼠狼在JAVA中可以这样定义

class 黄鼠狼{
    int 年龄;
    int 体重;
    void 吃鸡(){
        ...
    }
}
  • 类是蓝图或原型,它定义了所有某种类的对象的共有的变量和方法
  • 类是具有共同属性和行为的对象的抽象与集合

4.类

  • 类表示的一种类型,所以应用名词来表示,当出现两个或以上的单词时,第二个单词首字母总是大写,如类名:BankAccount

  • 类的定义基本语法

    [修饰符] class 类名 [extends 父类][implements 接口名]{
        //类成员变量声明
        //类方法声明
    }
    

    说明:

    (1)修饰符: 分为访问控制符、抽象类说明符和最终类说明符三种

    • 访问控制符:public、private、protected
    • 抽象类说明符:abstract
    • 最终类修饰符:final

    (2)extends 父类:当前类是某个已经存在类的子类

    (3)implements 接口名:当前类实现了某个已经存在的接口定义的方法

    (4)[ ]表示可选

    (5)若一个类同时又继承关系和实现关系时,必须先继承再实现,即extends写在implements前面,而这位置不可颠倒

    (6)权限修饰符的位置可以颠倒

5.类的属性

  • 属性表示的是一种状态,用名词,一般首字母小写第二个单词大写,为常量时全部大写多个单词下划线分割。

  • 类属性定义基本语法

    [修饰符] 变量类型 变量名 [ = 变量初始值]
    

    说明:

    (1)修饰符:访问修饰符、静态修饰符、最终修饰符

    • 访问修饰符 public、private、protected
    • 静态修饰符 static
    • 最终修饰符 final

    (2)变量类型:基本数据类型、引用数据类型

    • 基本数据类型(四类八种)
      • 整型:byte、short、int、long 默认初始值为0
      • 浮点型:float、double 默认初始值为0.0
      • 字符型:char 默认初始值 \u0000
      • 布尔型:boolean 默认初始之false
    • 引用数据类型:String(字符串型)、各种类 默认初始值null

    For example

    public class Person {
        public String name="张帅";// 字符串类型
        private int age = 23;// 整数类型
    }
    

    当我们定义了Person类,Person就可以是一个引用数据类型

6.类的方法

  • 方法表示的是能做什么,用动词,当出现两个或以上的单词时,第二个单词首字母总是大写,如方法名:fetchMoney

  • 类的方法基本语法

    [修饰符] 返回值类型 方法名(参数类型 参数1,参数类型 参数2...)[throws 异常]{
        //逻辑语句;
    }
    

    说明:

    (1)修饰符:访问控制符、静态修饰符、抽象修饰符、最终修饰符

    • 访问控制符:public、private、protected
    • 静态修饰符:static
    • 抽象修饰符:abstract
    • 最终修饰符:final

    (2)返回值类型void(无返回值的方法)和 数据类型(有返回值的方法)【❤】

    (3)参数列表:多个参数用逗号隔开也可没有参数

    (4)[ ]表示可选,throws属于异常处理内容

    对❤的补充

    • 方法中返回值需要使用return关键字

    • 无返回值的方法可以有return,此时的作用是用于方法的结束,类似循环语句中的break

    • 有返回值的方法必须要有return,且返回的类型要与方法的返回值类型保持一致,注意当方法有if语句时,需要判断之后返回return必须要在else里也要return,即if和else都需要有return即使else没有逻辑else也需要写。

      public class Test {
          public Test compare(int a, int b){
              if (a > b){
                  return new Test();
              }else {
                  return null;//省略else报错,因为此方法可能进不了if里导致此方法没有了返回值
              }
          }
          public void div(int a, int b){
              if(b == 0){
                  return;//如果b=0,此方法结束,此时的return作为方法的结束
              }
              System.out.println(a/b);
          }
      }
      

7.定义一个Person类

  public class Person {
      public String name;
      public int age;

      public void run(){
          System.out.println("人会跑");
      }
      public void sleep(){
          System.out.println("人要睡觉");
      }
  }

8.构造方法

作用:用户创建对象的时候做初始化工作

特征:

  • 方法名与类名一致
  • 方法没有返回值
  • 不能被继承
  • 可以被重载,即一个类可以有很多个构造方法【有参构造、无参构造】
  • 当我们定义类时没有写构造方法如上面的Person类,系统默认提供一个构造方法,此构造方法没有参数也没有方法体
  • 构造方法可以被私有化,构造方法时可以被私有化的,但此时我们无法再实例化这个类,因此通常会提供一个公共的访问接口,参考单例设计模式。

    构造方法的语法

    [修饰符] 类名(参数表){
      //方法体
    }
    

    注意:当我们写了构造方法时,系统将不再提供默认的构造方法,因此当我们写了有参构造通常会写一个无参构造。

    public class Person {
      public String name;
      public int age;
      //无参构造
      public Person() {
      }
      //有参构造
      public Person(String name, int age) {
          this.name = name;
          this.age = age;
      }
    
      public void run(){
          System.out.println("人会跑");
      }
      public void sleep(){
          System.out.println("人要睡觉");
      }
    
      public static void main(String[] args) {
          Person person1 = new Person();//若没有无参构造,就会报错
          Person person2 = new Person("张三",21);
      }
    }
    

9.对象的生命周期

对象的创建 –> 对象的使用 –> 对象的清除

(1)对象的创建

  • new关键字创建对象
  • 一些特殊的类可以通过多态创建[抽象类、接口]

(2)对象的使用【不考虑权限问题】

  • 对象.属性名
  • 对象.方法名

(3)对象的清除

  • 由gc垃圾回收自动清除,一般不需要干预finalize()

10.实例化对象

语法格式

类型名 引用变量 = new 构造器(构造器的参数)

说明:

(1)为了声明一个变量来引用对象,你可以使用类或者接口的名字作为变量的类型

(2)声明并没有创建新对象。在对该引用变量赋值前,该引用为空,称为空引用(null)

(3)new操作符通过为新对象分配内存来实例化一个类

(4)new操作符需要一个后缀参数,即构造器的一个调用

(5)new操作符返回一个对它所创建对象的引用,通常该引用被赋值给具有适当类型的引用变量

(6)如果new操作符返回的引用没有被赋给任何变量,那么当new操作符所在的语句执行完后,将无法访问该对象,参考匿名对象

11.补充

目前为止的赋值操作顺序

public class Test {
    public static void main(String[] args) {
        Num num = new Num();
    }
}
class Num{
    public int a = 1;
    public String b;
    public Num(){
        a = 1;
        b = "abc";
    }
}

(1)第一步:声明一个整型变量a,JVM赋初值0;声明一个字符串变量b,JVM赋初值null

(2)第二部:JVM赋初值,定义成员变量a时手动赋1;

(3)构造器赋值:a = 1;b = “abc”;

即:JVM赋初值 > 定义成员变量手动赋值 > 构造器赋值操作

二、面向对象的三大特征

封装、继承和多态

  • 封装:在也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。

  • 继承: 继承就像是我们现实生活中的父子关系,儿子可以遗传父亲的一些特性,在面向对象语言中,就是一个类可以继承另一个类的一些特性,从而可以代码重用,其实继承体现的是is-a关系,父类同子类在本质上还是一类实体。

  • 多态:多态就是通过传递给父类对象引用不同的子类对象从而表现出不同的行为,多态可为程序提供更好的可扩展性,同样也可以代码重用。

To Be Continue…

三、集合框架

一、概述

1.数组

  • 特点
    • 一旦开辟空间,长度固定
    • 内存连续
    • 支持索引
    • 一个对应类型的数组只能存放这种数据类型的数据

2.集合框架

  • 特点
    • 长度可变
    • 创建一个集合可以存储任何的引用数据类型(存储对象的地址值)
    • 根据底层的数据结构,其地址可能连续可能不连续
    • 使用接口来组织结构体系的
  • 集合框架分类
    • 单列集合:一次只能存储一个数据
    • 双列集合:一次存储一对数据

二、单列集合父接口Collection

1.分类

  • List接口:可存储重复元素
  • Set接口:不可存储重复元素

2.方法

boolean add(E e)    //添加元素到集合,添加的元素是一个对象,注意和addAll()的区别
boolean addAll(Collection<? extends E> c)    //把一个集合里的元素以此添加到当前集合中
void clear()    //清空当前集合
boolean contains(Object o)        //判断对象o是否在当前容器中,底层使用的是equals
boolean containsAll(Collection<? extends E> c)    //判断容器c所有的元素是否在当前容器中
boolean isEmpty()    //判断当前容器是否为空
boolean remove(Object o)    //从当前集合移除对象o,成功返回true
boolean removeAll(Collection<? extends E> c)    //从当前集合移除容器里所有的对象,只要有成功的就返回true
boolean retainAll(Collection<?> c)    //保留当前集合和容器c的交集,改变会当前集合
int size()    //返回当前集合的长度
Object[] toArray()    //集合转数组
Arrays.toList(T... a)    //数组转List

3.代码实现

package Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class Demo1 {
    public static void main(String[] args) {
        Collection<String> c1 = new ArrayList<>();
        Collection<String> c2 = new ArrayList<>();

        c1.add("a");
        c1.add("b");
        c2.add("a");
        c2.add("d");

        System.out.println(c1);
        System.out.println(c2);

        c1.addAll(c2);
        System.out.println(c1);
        System.out.println(c1.contains("a"));
        System.out.println(c1.contains("c"));

        c1.containsAll(c2);
        System.out.println(c1.isEmpty());
        System.out.println(c2.remove("c"));
        System.out.println(c2.size());
        System.out.println(c1.removeAll(c2));
        System.out.println(c1);

        Object[] objects = c1.toArray();
        System.out.println(Arrays.toString(objects));
        List<Integer> list = Arrays.asList(1, 2, 3);
        System.out.println(list);
    }
}

三、List

1.特点

  • 可以存储重复元素
  • 有序,支持索引

2.实现类

ArrayList:底层使用可变长数组实现,读取数据效率高,但是增删慢,线程不安全         
LinkedList:底层采用双向链表实现。内存不连续,读取效率不高,线程不安全,增删效率高。            
Vector:底层使用可变长数组实现,读取数据效率高,但是增删慢,线程不安全

3.特有方法

void add(int index, E element)    //将指定的元素插入此列表中的指定位置
boolean addAll(int index, Collection<? extends E> c) //将指定集合中的所有元素插入到此列表中的指定位置
boolean equals(Object o)    //将指定的对象与此列表进行比较以获得相等性。当且仅当指定的对象也是列表时,两个列表都具有相同的大小,并且两个列表中所有相应的元素对相等返回true
E get(int index)     //返回此列表中指定位置的元素。
int indexOf(Object o)     //返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 
int lastIndexOf(Object o) //返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。 
E set(int index, E element) //用指定的元素(可选操作)替换此列表中指定位置的元素。
E remove(int index) //删除该列表中指定位置的元素(可选操作)。
List<E> subList(int fromIndex, int toIndex) //返回此列表中指定的 fromIndex (含)和 toIndex之间的部分。 
default void sort(Comparator<? super E> c) //使用随附的 Comparator排序此列表来比较元素。  

4.代码实现

package Test;

import java.util.*;

public class Demo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("c");
        list.add(1, "b");
        System.out.println(list);

        list.addAll(list);
        System.out.println(list);

        System.out.println(list.get(1));
        System.out.println(list.indexOf("b"));
        System.out.println(list.lastIndexOf("b"));

        list.set(5, "e");
        list.remove(1);
        List<String> list1 = list.subList(1, 3);
        System.out.println(list1);

        /**
         * 匿名内部类
         */
        List<Integer> list3 = Arrays.asList(1, 2, 4, 6, 9, 3);
        list3.sort(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //向下转型要注意是否有继承关系
                Integer i1 = (Integer) o1;
                Integer i2 = (Integer) o2;
                return (i1 - i2);
            }
        });
        System.out.println(list3);
    }
}

四、ArrayList

用法见List。底层使用可变长数组实现,读取数据效率高,但是增删慢,线程不安全

五、LinkedList

底层采用双向链表实现。内存不连续,读取效率不高,线程不安全,增删效率高

1.特有方法

void addFirst(E e) //在该列表开头插入指定的元素。 
void addLast(E e) //将指定的元素追加到此列表的末尾。 
E element() //获取但不删除此列表的头(第一个元素)。 底层调用gitFirst(),链表空报异常 
E getFirst() //返回此列表中的第一个元素。  
E getLast() //返回此列表中的最后一个元素。 
boolean offer(E e) //将指定的元素添加为此列表的尾部(最后一个元素)。 
boolean offerFirst(E e) //在此列表的前面插入指定的元素。  
boolean offerLast(E e) //在该列表的末尾插入指定的元素。  
E peek() //检索但不删除此列表的头(第一个元素)。 
E peekFirst() //检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。  
E peekLast() //检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null 。  
E poll() //检索并删除此列表的头(第一个元素)。  
E pollFirst() //检索并删除此列表的第一个元素,如果此列表为空,则返回 null 。  
E pollLast() //检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 。  
E pop() //从此列表表示的堆栈中弹出一个元素。  
void push(E e) //将元素推送到由此列表表示的堆栈上

2.代码实现

使用LinkedList实现栈和队列功能

package Collection;

import java.util.LinkedList;

/**
 * @Author: wjun
 * @Date: 2020/4/2 17:28
 * @Description: 栈 先进后出
 */
public class Stack<T> {
    private LinkedList<T> linkedList;

    public Stack() {
        linkedList = new LinkedList<>();
    }

    //判断栈是否为空
    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    //进栈
    public boolean add(T num) {
        return linkedList.add(num);
    }

    //出栈
    public T getElement() {
        if (isEmpty()){
            throw new RuntimeException("栈空...");
        }
        return linkedList.removeLast();
    }

    //查看当前栈
    public void showStack(){
        if (isEmpty()){
            System.out.println("栈空...");
            return;
        }
        System.out.println(linkedList);
    }
}

队列

package Collection;

import java.util.LinkedList;

/**
 * @Author: wjun
 * @Date: 2020/4/2 17:35
 * @Description: 队列 先进先出
 */
public class Queue<T> {
    private LinkedList<T> linkedList;

    public Queue(){
        linkedList = new LinkedList<>();
    }

    //判断队列是否为空
    public boolean isEmpty() {
        return linkedList.isEmpty();
    }

    //进队
    public boolean add(T num) {
        return linkedList.add(num);
    }

    //出队
    public T getElement() {
        if (isEmpty()){
            throw new RuntimeException("队列空...");
        }
        return linkedList.removeFirst();
    }

    //查看当前队列
    public void showQueue(){
        if (isEmpty()){
            System.out.println("队列空...");
            return;
        }
        System.out.println(linkedList);
    }
}

测试类

package Collection;

import java.util.Scanner;

/**
 * @Author: wjun
 * @Date: 2020/4/2 17:39
 * @Description:
 */
public class StackAndQueueTest {
    public static Scanner scanner = new Scanner(System.in);

    public static void main(String[] args) {
        while (true){
            System.out.println("1.测试栈");
            System.out.println("2.测试队列");
            System.out.println("3.退出");
            System.out.print(">>>");
            int op = scanner.nextInt();
            switch (op){
                case 1:
                    stackTest();
                    break;
                case 2:
                    queueTest();
                    break;
                case 3:
                    System.exit(0);
                default:
                    System.out.println("error...");
                    break;
            }
        }
    }
    public static void stackTest(){
        Stack<Integer> stack = new Stack<>();
        while (true){
            System.out.println("1.进栈");
            System.out.println("2.出栈");
            System.out.println("3.查看当前栈");
            System.out.println("4.退出");
            System.out.println("5.测试队列");
            System.out.print(">>>");
            int op = scanner.nextInt();
            switch (op){
                case 1:
                    System.out.print("进栈数>>>");
                    stack.add(scanner.nextInt());
                    break;
                case 2:
                    try {
                        System.out.println(stack.getElement());
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 3:
                    stack.showStack();
                    break;
                case 4:
                    System.exit(0);
                case 5:
                    queueTest();
                    break;
                default:
                    System.out.println("error...");
                    break;
            }
        }
    }

    public static void queueTest(){
        Queue<Integer> queue = new Queue<>();
        while (true){
            System.out.println("1.进队列");
            System.out.println("2.出队列");
            System.out.println("3.查看当前队列");
            System.out.println("4.退出");
            System.out.println("5.测试栈");
            System.out.print(">>>");
            int op = scanner.nextInt();
            switch (op){
                case 1:
                    System.out.print("进队列数>>>");
                    queue.add(scanner.nextInt());
                    break;
                case 2:
                    try {
                        System.out.println(queue.getElement());
                    }catch (Exception e){
                        System.out.println(e.getMessage());
                    }
                    break;
                case 3:
                    queue.showQueue();
                    break;
                case 4:
                    System.exit(0);
                case 5:
                    stackTest();
                    break;
                default:
                    System.out.println("error...");
                    break;
            }
        }
    }
}

六.迭代器Iterator

boolean hasNext()    //如果迭代具有更多的元素,则返回true(如果next()返回一个元素而不是抛出一个异常,则返回true )
E next()    //返回迭代中的下一个元素,没有可迭代元素抛出NoSuchElementException异常
default void remove()    //从底层集合中删除此迭代器返回的最后一个元素

1.代码实现

package Test;

import java.util.*;

public class Demo1 {
    public static void main(String[] args) {
        Collection<String> c1 = new ArrayList<>();
        c1.add("a");
        c1.add("b");
        c1.add("c");
        c1.add("d");
        Iterator<String> iterator = c1.iterator();//获取c1的迭代器对象
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

2.大坑

如果使用Iterator迭代器遍历集合,那么在遍历过程中如果使用容器对象对容器自身长度做了改变(例如:list.add(),remove虽然不会报异常,但是无法正常迭代),那么可能会发生并发修改异常,我们可以通过调用迭代器的remove()方法,实现删除元素功能,保证集合正常迭代。

如果我们有需求在迭代list的时候改变集合长度的操作,可以使用list特有的迭代器ListIterator,然后调用ListIterator接口的中相关操作方法。

package Test;

import java.util.*;

public class Demo1 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        ArrayList<Integer> list1 = new ArrayList<>(list);
        ListIterator<Integer> iterator = list1.listIterator();
        while (iterator.hasNext()){
            Integer integer = iterator.next();
            if (integer == 3){
                //list1.remove(3);//并发修改异常
                iterator.remove();
            }
            System.out.println(integer);
        }
    }
}

四、泛型

一.作用

  • 保证集合容器中的数据是安全的。
  • 避免类类型转换异常
  • 避免编译器出现警告

注:

  • 泛型的检查是在编译期间进行,运行期间泛型擦除。
  • 集合泛型前后保持一致
  • 不同泛型的引用变量之间不能相互赋值
  • 泛型只能是引用类型,不能是基本数据类型

二、使用场景

  • 集合使用泛型

  • 在方法参数使用泛型或者泛型方法

泛型方法:

  • 修饰符 泛型 返回值 方法名(参数列表)throws 异常类型
  • 自定义泛型类或者泛型接口

三、泛型继承

List<?>  list:泛型是Object
List<?  extends  E>  list:泛型是E类型或者E的子类类型
List<?  super  E>  list:泛型是E类型或者E的父类类型

四、代码实现

package Reflect;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: wjun
 * @Date: 2020/4/2 8:57
 * @Description:
 */
public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("list");
        System.out.println(list);
    }

    public static <T> void test(List<? extends T> list) {
    }

    public static <T> void run(List<? super T> list) {
    }
}

只喜欢学习