【编程语言】Java3

【编程语言】Java2

【编程语言】Java4

day9

代码块

public class Person {
    String name;

    public Person(){
        this.name = "pipi";
        System.out.println("执行的是构造方法");
    }

    // 非静态代码块
    {
        System.out.println("执行的是非静态代码块 1");
    }
    {
        System.out.println("执行的是非静态代码块 2");
    }
    {
        System.out.println("执行的是非静态代码块 3");
    }

    public static void main(String[] args) {
        new Person();
    }
}

//非静态代码块是按照顺序执行的。
//output
//执行的是非静态代码块 1
//执行的是非静态代码块 2
//执行的是非静态代码块 3
//执行的是构造方法

一个类中初始化块若有修饰符,则只能被static修饰,称为静态代码块(static block),当类被载入时,类属性的声明和静态代码块先后顺序被执行,且只能被执行一次。 

问:这里为什么不用this.age?

答:因为static是类方法,类加载的时候就创建了,this指的是对象,实例化以后才有,所以不能用。

public class Person {
    String name;
    static int age;

    public Person(){
        this.name = "pipi";
        System.out.println("执行的是构造方法");
    }

    // 非静态代码块
    {
        System.out.println("执行的是非静态代码块 1");
    }
    {
        System.out.println("执行的是非静态代码块 2");
    }
    {
        System.out.println("执行的是非静态代码块 3");
    }

    // 静态代码块
    static {
        //这里只能使用静态static修饰的属性和方法
        System.out.println("=====执行的是静态代码块======");
        age = 1;
        showAge();
    }

    public static void showAge(){
        System.out.println(age);
    }


    public static void main(String[] args) {
        new Person();
        new Person();
    }
}
/*
=====执行的是静态代码块======
        1
        执行的是非静态代码块 1
        执行的是非静态代码块 2
        执行的是非静态代码块 3
        执行的是构造方法
        执行的是非静态代码块 1
        执行的是非静态代码块 2
        执行的是非静态代码块 3
        执行的是构造方法
        
 */

如果没有代码块呢?println()提示报错(java: 需要<标识符>),不能再类里直接sout。

非静态代码块:没有static修饰的代码块

  1. 可以有输出语句;
  2. 可以对类的属性声明进行初始化操作;
  3. 可以调用静态和非静态的变量或方法;
  4. 若有多个非静态的代码块,那么按照从上到下的顺序依次执行;
  5. 每次创建对象的时候,都会执行一次。且优先于构造函数执行。

静态代码块:用static修饰的代码块

  1. 可以有输出语句;
  2. 可以对类的属性声明进行初始化操作;
  3. 不可以对非静态的属性初始化。即:不可以调用非静态的属性的和方法;
  4. 若有多个静态的代码块,那么按照从上到下的顺序依次执行;
  5. 静态代码块的执行要优先于非静态代码块;
  6. 静态代码块只执行一次。

在实际开发中,static静态代码块用在初始化类的静态属性(static类型属性)

简单属性static int age =1;即可,但是类属性时,

public class Person2 {
    // 变量声明
    String name;
    static int age = 1; // 简单属性static int age =1; 即可t
    static Person2 tp = new Person2(); // 需要设置

    public Person2(){
        this.name = "pipi";
        System.out.println("执行的是构造方法");
    }

    {
        System.out.println("执行的是非静态代码块 1");
        System.out.println("执行的是非静态代码块 2");
        System.out.println("执行的是非静态代码块 3");
    }

    // 静态代码块
    static {
        //这里只能使用静态static修饰的属性和方法
        age = 1;
        showAge();
        System.out.println("=====执行的是静态代码块======");
        // 这里设置类属性
        tp.name = "";
        tp.age = 100;
    }

    public static void showAge(){
        System.out.println("showAge return: " + age);
    }

    public static void main(String[] args) {
        System.out.println("***** main中的实例化 *****");
        new Person2();
        new Person2();
        System.out.println("***********************");

    }
}

/*
* 以下结果中,可以看出先运行的部分是代码的变量声明
*
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
showAge return: 1
=====执行的是静态代码块======
***** main中的实例化 *****
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
执行的是非静态代码块 1
执行的是非静态代码块 2
执行的是非静态代码块 3
执行的是构造方法
***********************
 */

这里没听懂?

为什么非要这样写呢?

代码块在匿名类内部使用是无可替代的, 因为用不了构造方法,因为构造需要类名,匿名类没有类名,就不能用构造,所以需要其他方法来初始化各种属性,所以用代码块来初始化。(代码块在匿名的内部类中用来初始化属性

java除了老版本中的东西以外,其他现存的这些东西,都是有作用的。而且是在某一个方式有不可替代的作用。 

关键字final

在java中声明类、属性和方法时,可以使用关键字final来修饰,表示“最终”。

  • final标记的类不能被继承。提高安全性、提高程序的可读性。e.g. String类、System类、StringBuffer类
  • final标记的方法不能被子类重写。 e.g. Object类中的getClass()。
  • final标记的变量(成员变量或局部变量)即为常量。名称大写,且只能被赋值一次;

e.g. final标记的成员变量必须在声明的同时、或在每个构造方法中、或代码块中显式赋值,然后才能使用。

e.g. final double PI = 3.14;

1、final修饰类

2、final修饰方法不能被子类重写

(下面这个写了两个类在同一个文件中,去掉final就可以运行了)。一个类里只能写一个类,如下会报错,这样放在一起只是为了方便。

3、final修饰常量(全局常量是什么意思?final static一起修饰变量,就是全局常量)

总结:

抽象类

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。

有时,将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类就做抽象类。

  • 用abstract关键字来修饰一个类时,这个类叫做抽象类;
  • 用abstract来修饰一个方法时,该方法叫做抽象方法。

抽象方法:只有方法的声明,没有方法的实现。以分号结束:abstract int abstractMethod (int a);

只要类中有一个抽象方法,那么这个类就必须是一个抽象类。

  •  含有抽象方法的类必须被声明为抽象类。
  • 抽象类不能被实例化。抽象类是用来作为父类被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
  • 不能用abstract修饰属性、私有方法、构造方法、静态方法、final的方法。

抽象类举例

很奇怪,这些类竟然可以放在一个Animal.java文件中。

public abstract class Animal {
    // 只要类中有个一个抽象方法,类就必须是一个抽象类
    public abstract void test();

    public abstract void move();

//    public static void main(String[] args) {
//        Dog d = new Dog();
//        d.move(); //狗的移动方式是run...
//    }
}

class Dog extends Animal{
    //Class 'Dog' must either be declared abstract or implement abstract method 'test()' in 'Animal'

    @Override
    public void test() {
        System.out.println("dog...");
    }

    @Override
    public void move() {
        System.out.println("狗的移动方式是run...");
    }
}

class Fish extends Animal{
    @Override
    public void test() {

    }

    @Override
    public void move() {
        System.out.println("鱼的移动方式是swim...");
    }
}

//抽象类可以继承抽象类
abstract class Bird extends Animal{
    @Override
    public void move() {

    }
    public abstract void test();// 只要类中有个一个抽象方法,类就必须是一个抽象类
}
public class Test {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.move(); //狗的移动方式是run...
    }
}

抽象类是用来模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类。

例如,在航运公司系统中,Vichle类需要定义两个方法分别计算运输工具的燃料效率行驶距离。 

问题:卡车Truck和驳船RiverBarge的燃料效率和行驶距离的计算方式完全不同。Vehicle类不能提供计算方法,但子类可以。

思考

Q1:为什么抽象类不可以使用final关键字声明?

A1:抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。

final是最终,它修饰的类是最终的类,不能被继承。而抽象类,如果想要使用,必须继承抽象类,实现那么抽象的方法。

Q2:一个抽象类中可以定义构造方法吗?

A2:抽象类可以有构造方法,只是不能直接创建抽象类的实例对象而已。

抽象类不能实例化,new Vihicle()是非法的。

练习

public abstract class Emplyee {
    public Emplyee() {
    }

    int id;
    String name;
    int salay;

    public abstract void work();
}

class CommonEmployee extends Emplyee{

    public void setCommonEmployeeInfo(int id, String name, int salay) {
        super.id = id;
        super.name = name;
        super.salay = salay;
    }

    public void getCommonEmployeeInfo() {
        System.out.println(super.id);
        System.out.println(super.name);
        System.out.println(super.salay);
    }

    @Override
    public void work() {
        System.out.println("这是一个普通员工");
    }
}

class Manger extends Emplyee{
    double bouns;
    public void setMangerInfo(int id, String name, int salay, double bouns){
        super.id = id;
        super.name = name;
        super.salay = salay;

        this.bouns = bouns;
    }

    public void getMangerInfo(){

    }

    @Override
    public void work() {
        System.out.println("这是领导");
    }
}
public class Test {
    public static void main(String[] args) {
//        Dog d = new Dog();
//        d.move(); //狗的移动方式是run...
        CommonEmployee ce = new CommonEmployee();
        ce.work(); //这是一个普通员工
        ce.setCommonEmployeeInfo(123,"poppy",15000);
        ce.getCommonEmployeeInfo();//123
//        poppy
//        15000

        Manger m = new Manger();
        m.work(); //这是领导
    }
}

 


模板设计模式

模板方法设计模式

public abstract class Template {
    public abstract void code();

    public final void getTime(){
        long start = System.currentTimeMillis();
        code();
        long end = System.currentTimeMillis();
        System.out.println("codef方法的执行时间是:" + (end-start));
    }

}

class SubTemplate extends Template{
    @Override
    public void code(){
        int k = 0;
        for (int i = 0; i<1000; i++){
            k += i;
        }
        System.out.println(k);
    }
}
public class TestTemplate {

    public static void main(String[] args) {
        SubTemplate t = new SubTemplate();
        t.getTime();
    }
}

//499500
//codef方法的执行时间是:1

接口

另一种抽象方式:

  • 有时必须从几个类中派生出一个子类,继承他们所有的属性和方法。但是java不支持多重继承。有了接口,就可以得到多重继承的效果。
  • 接口interface是抽象方法和常量值的定义的集合。
  • 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
  • 实现接口类:class SubClass implements InterfaceA{ }
  • 一个类可以实现多个接口,接口也可以继承其他接口。

接口的特点:

  • 用interface来定义;
  • 接口中的所有成员变量都默认是由public static final修饰的;
  • 接口中的所有方法都默认是由public abstract修饰的;
  • 接口没有构造方法;
  • 接口采用多层继承机制。

举例: 

代码实现

package course03;

public interface TestIn {
    int ID = 1; //等同于public static final int ID = 1;
    void test(); //public abstract void test();
}
package course03;

public interface TestInOne {
    void test1();

}
package course03;

// 接口可以继承
public interface TestInTwo extends TestInOne {
    // 必须要重写方法,否则报错

}
package course03;
//TestInImp1是个类,有了多个功能
public class TestInImp1 implements TestIn, TestInOne {
    @Override
    public void test() {

    }

    @Override
    public void test1() {

    }
}
  • 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
  • 接口的主要用途就是被实现类实现。(面向接口编程)
  • 与继承关系相似,接口与实现类之间存在多调性。

举例: 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。

如果类没有实现接口所有方法,这个类就要定义为抽象类。

问题:接口和抽象类很相似,好像接口能做的事用抽象类也能做,为什么还要用接口呢? 

为什么需要用接口(1)?

为什么需要用接口(2)?

父类Person类

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

    public abstract void showInfo();
    //抽象类中不用具体实现方法内容
}

唱歌、厨艺接口

/*
唱歌的接口
*/
public interface Sing {
    void singing();
}
/*
* 厨艺的接口
* */
public interface Cooking {
    void fry(); //炒菜
}

 这个是描述会唱歌的厨子是一个老师的类

//一个类可以实现多个无关的接口Cooking\Sing
//接口Cooking\Sing
//实现类SCTeacher
public class SCTeacher extends Person implements Cooking, Sing {
    String courese;//教的科目
    public void setInfo(){
        super.age = 27;
        super.name = "pp";
        super.sex = 1;

        this.courese = "计算机";
    }

    // 重写父类的方法
    @Override
    public void showInfo() {
        System.out.println("会唱歌,会做饭的老师的信息时:");
        System.out.println("年龄:" + super.age);
        System.out.println("姓名:" + super.name);
        System.out.println("性别:" + super.sex);
        System.out.println("课程:" + this.courese);
    }

    @Override
    public void fry() {
        System.out.println(super.name + "老师拿手的厨艺是炒菜");
    }

    @Override
    public void singing() {
        System.out.println(super.name + "老师擅长流行歌");
    }

    //调用
    public static void main(String[] args) {
        SCTeacher sct = new SCTeacher();
        sct.setInfo();
        sct.showInfo();
        sct.fry();
        sct.singing();

        System.out.println("*********************");
        // 接口的多态
        Cooking c = new SCTeacher();
        c.fry();

        Sing s = new SCTeacher();
        s.singing();
    }
}

/*
会唱歌,会做饭的老师的信息时:
年龄:27
姓名:pp
性别:1
课程:计算机
pp老师拿手的厨艺是炒菜
pp老师擅长流行歌
*********************
null老师拿手的厨艺是炒菜
null老师擅长流行歌


Process finished with exit code 0
*/

与继承关系相似,接口与实现类之间存在多态性

上述代码,可用接口来接收实例对象

  • 如果实现接口的类中,没有实现接口中的全部方法,必须将此类定义为抽象类。
  • 接口也可以继承另一个接口,使用extends关键字。
  • 类需要必须实现接口中的全部方法。

抽象类是对于一类事物的高度抽象,其中既有属性也有方法。接口是对方法的抽象,也就是对一系列动作的抽象。

当需要对一类事物抽象的时候,应该是使用抽象类,好形成一个父类。

当需要对一系列的动作抽象,就使用接口,需要使用这些动作的类去实现相应的接口即可。


工厂模式

建立一个返回值为BWM类的对象的抽象方法,该方法是生产汽车的,为后面具体的汽车空间提高方法。

接口内是一个(抽象)函数,返回值是BWM的类,下面具体实现这个函数。

以下实现:汽车生产工厂接口

这里修改并不影响:

这节课没有听懂。


 

内部类

一个类的内部再写一个类,可以调用类的其他变量,和方法一样?

  • 在jiava中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
  • Inner class一般用在定义它的类或语句块之间,在外部引用它时必须给出完整的名称。Inner class的名字不能与包含它的类名相同;
  • Inner class可以使用外部类的私有数据,因为它是外部类的成员,同一个类的成员之间可以相互访问。而外部类要访问内部类的成员需要:内部类.成员 or 内部类对象.成员;
  • 分类:成员内部类(static成员内部类和非static成员内部类)
  • 局部内部类(不谈修饰符)、匿名内部类。

举例:

public class Test {
    int i;
    public int z;
    private int k;

    class A{
        int i;

        //class A里的set方法是为了要使用int i等三个属性的,使用属性需要方法。所以写此set方法。
        public void setTestFileds(){
            Test.this.i = 1;
            Test.this.z = 2;
            Test.this.k = 3;
        }

//        public void set(){
//            this.i = 10;
//        }
    }

    public void setInfo(){
        //调用内部类
        //内部类也是一个类啊
        new A().setTestFileds(); // 外部的类要使用自己的内部类Class A的方法,得先new内部类的对象
        System.out.println("*********");
//        new A().set();
    }

    public void showInfo(){
        System.out.println(this.i);
        System.out.println(this.z);
        System.out.println(this.k);
    }

    public static void main(String[] args) {
        Test t = new Test();
        t.setInfo();
        t.showInfo();
    }
}
/*
*********
1
2
3
* * */

内部类特性

内部类的最大作用是实现多重继承

Inner class作为类的成员:

  • 可以声明为final的;
  • 和外部类不同,inner class可以声明为private或protected;
  • inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;

Inner class作为类:

  • 可以声明为abstract类,因此可以被其他内部类继承;

【注意】非static的内部类中的成员不能声明为static的,只有在外部类或static的内部类中才可以声明static成员。

问题:内部类有什么用?外面也能写

内部类主要是解决java不能多重继承的问题。(接口是方法,类有其他属性,接口可以有属性吗?)

接口的属性在实现类中不能被使用,e.g.

内部类举例,文件结构如下: 

 

import javax.crypto.spec.PSource;

public class Test2 {
    public static void main(String[] args) {
        A a = new A();
        a.testB();
        a.testC();
    }
    /*
    A类中调用B类的变量:1000
    这是重写之后的testB方法
    父类B中的成员变量:1000
    这是重写之后的testC方法
    * */
}

/*
* 如果类A想同时获得类B和类C的方法,并且重写
* 可以使用内部类来变相的实现类的多重继承,可以同时继承多个类
* */
class A {
    public void testB(){
        System.out.println("A类中调用B类的变量:" + new InnerB().a);
        new InnerB().testB();
    }

    public void testC(){
        new InnerC().testC();
    }

    private class InnerB extends B{
        int a = super.bb; // 可以这样赋值
        @Override
        public void testB() {
//            super.testB();
            System.out.println("这是重写之后的testB方法");
            System.out.println("父类B中的成员变量:" + super.bb);
        }

    }

    private class InnerC extends C{
        @Override
        public void testC() {
//            super.testC();
            System.out.println("这是重写之后的testC方法");
        }
    }
}

class B{
    // 问题?继承的时候成员可以继承吗?可以super.
    int bb = 1000;
    public void testB(){
    }
}

class C{
    public void testC(){

    }
}

面向对象总结


day10

异常

数组越界异常

空指针异常

java异常类层次

捕获异常

异常处理机制

try catch时没必要说明具体类型,即可。

抛出异常

举例

重写方法声明抛出异常的原则

子类重写父类的方法是,子类不能抛出比父类方法更大范围的异常。

举例

人工抛出异常

创建用户自定义异常类 

一般轮不到自己写!


 

java集合概述

  • 集合只能存放对象比如你存一个int型数据1放入集合中,其实它是自动转换成Interger类后存入的,java中每一种基本类型都有对应的引用类型。
  • 集合存放的是多个对象的引用,对象本身还是存放在堆内存中。
  • 集合可以存放不同类型,不限数量的数据类型。

HashSet集合

hashset是set接口的典型实现,大多数时候使用set集合时都使用这个实现类。我们大多数时候说的set集合指的都是hashset。

hashset按hash算法来存储集合中的元素,因此具有很好的存取和查找性能。

hashset具有以下特点:

  • 不能保证元素的排列顺序
  • 不可以重复
  • hashset不是线程安全的
  • 集合元素可以使用null

当向hashset集合中存入一个元素时,hashset会调用该对象的hashcode()方法来得到该对象的hashcode值,然后根据hashcode值决定该对象在hashset中的存储位置。

如果两个元素的equals()方法返回ture,但是它们的hashcode()返回值不相等,hashset将会把它们存储在不同的位置,但依然可以添加成功。

举例:不保证元素的排列顺序

不可重复指的是hashcode不相同。一般情况,equals和hashcode返回结果一致。

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class TestHash {
    public static void main(String[] args) {
        Set seta = new HashSet();
        seta.add(1); // 添加元素
        seta.add("a");

        System.out.println(seta); //[1, a]
        seta.remove(1); //移除元素
        System.out.println(seta); //[a]

        //判断是否包含元素1
        System.out.println(seta.contains(1)); //false
        seta.clear(); //清空集合
        System.out.println(seta); //[]

        seta.add("b");
        seta.add("c");
        seta.add("d");
        System.out.println(seta); //[b, c, d]
        System.out.println("------------------");

        //使用迭代器遍历集合
        Iterator it = seta.iterator();

        while (it.hasNext()){
            System.out.println(it.next());
        }

        //for each迭代
        //这个的意思是把set的每一个值取出来,赋值给obj,直到循环seta的所有值
        for (Object obj : seta){
            System.out.println(obj);
        }
        //b
        //c
        //d

        //获取集合的大小
        System.out.println(seta.size()); //3

        //set集合不重复
        seta.add("d");
        seta.add(null);
        System.out.println(seta); //[null, b, c, d]

    }
}

hashset集合判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashcode()方法返回值也相等。

如果两个对象通过equals()方法返回ture,这两个对象的hashcode值也应该相同。

如果想要让集合只能存同样类型的对象,则使用泛型

import java.util.HashSet;
import java.util.Set;

public class TestHash {
    public static void main(String[] args) {

        //使用泛型,则集合只能存同样类型的对象
        //比如指定string为集合的泛型,那么这个集合不能存string类型之外的
        Set<String> set1 = new HashSet<String>();
        set1.add("abc");
//        set1.add(1); //error
        
        //set2\set3 等价
        Set set2 = new HashSet(); //Raw use of parameterized class 'Set'
        Set<Object> set3 = new HashSet<Object>(); 

    }
}

TreeSet集合

TressSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。

TreeSet支持两个排序方法:自然排序和定制排序。默认情况下,采用自然排序。

自然排序

排序:TreeSet会调用集合元素的compareTo(Object  obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列。

  • 如果this>obj,返回整数1;
  • 如果this<obj,返回整数-1;
  • 如果this=obj,返回整数0,则认为这两个对象相等;
  • 必须放入同样类的对象。(默认会进行排序)否则可能会发生类型转换异常。我们可以使用泛型来进行限制。

 

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class TestTree {
    public static void main(String[] args) {
        Set<Integer> set1 = new TreeSet<Integer>();
        //自然排序
        set1.add(5);
        set1.add(4);
        set1.add(2);
        set1.add(3);
        System.out.println(set1); //[2, 3, 4, 5]

        //遍历
        //1 使用迭代器遍历集合
        Iterator<Integer> it = set1.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

        //2 for each迭代集合,推荐使用这种
        for (Integer i : set1) {
            System.out.println(i);
        }
        //2
        //3
        //4
        //5

        set1.remove(5);
        System.out.println(set1); //[2, 3, 4]
        System.out.println(set1.contains(3)); //true
        set1.clear();
    }
}

集合是可以存各种数据的(类)

import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

//把person对象存到TreeSet中,并且按照年龄排序
//Comparator接口的实现类
public class Person implements Comparator<Person> {
    int age;
    String name;

    // 之前不懂为什么要有这个无参构造。
    // 无参构造,为了Person comparator = new Person();
    public Person(){

    }

    //构造函数
    public Person(String name, int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public int compare(Person o1, Person o2) {
        //年龄正排序
        if (o1.age > o2.age){
            return 1;
        }else if(o1.age < o2.age){
            return -1;
        }else {
            return 0;
        }
    }

    public static void main(String[] args) {
        Person p1 = new Person("A", 23);
        Person p2 = new Person("B", 20);
        Person p3 = new Person("C", 16);
        Person p4 = new Person("D", 29);

        //new Person(),没有无参构造,这句报错
        Set<Person> setp = new TreeSet<Person>(new Person());
        setp.add(p1);
        setp.add(p2);
        setp.add(p3);
        setp.add(p4);

        for (Person p: setp
             ) {
            System.out.println(p.name + " " + p.age);
        }
    }
}
//C 16
//B 20
//A 23
//D 29

另一种实现,https://www.cnblogs.com/huhx/p/comparableAndcomparator.html

 

 

 

以上就是定制排序:如果需要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator接口的实现类对象。由该Comparator对象负责集合元素的排序逻辑。

 

List集合

  • List代表一个元素有序、且可以重复的集合,集合中的每个元素都有其对应的顺序索引。
  • List允许使用重复元素,可以通过索引来访问指定位置的集合元素。
  • List默认按元素的添加顺序设置元素的索引。
  • List集合里添加了一些根据索引来操作集合元素的方法。

 

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

public class TestList {
    public static void main(String[] args) {
        List<String> lista = new ArrayList<String>();
        lista.add("b");
        lista.add("c");
        lista.add("d");
        lista.add("a");
        lista.add("a"); //可以重复

        System.out.println(lista); //[b, c, d, a, a]
        //通过索引来访问指定位置的元素集合
        System.out.println(lista.get(2)); //d

        //在指定索引下标的位置插入数据
        lista.add(1,"f");
        System.out.println(lista); //[b, f, c, d, a, a]

        System.out.println("---------------------------------");
        List<String> listb = new ArrayList<String>();
        listb.add("123");
        listb.add("456");


        lista.addAll(2,listb); //在指定位置上插入新的集合

        System.out.println(lista); //[b, f, 123, 456, c, d, a, a]

        //获取指定元素在集合中第一次出现的索引下标
        System.out.println(lista.indexOf("a")); //6
        //获取指定元素在集合中最后一次出现的索引下标
        System.out.println(lista.lastIndexOf("a")); //7

        //根据指定下标移除元素
        lista.remove(2);
        System.out.println(lista); //[b, f, 456, c, d, a, a]

        // 根据指定的索引下标修改元素
        lista.set(1,"ff");
        System.out.println(lista); //[b, ff, 456, c, d, a, a]

        //根据索引下标的起始位置截取一段元素形成一个新的集合,
        //截取的时候,包含开始的索引,不包含结束的索引
        List<String> sublist = lista.subList(2,4);
        System.out.println(sublist); //[456, c]
    }
}

arraylist与vector(两种方法差不多)

 

arraylist和vector是list接口的两个典型实现,区别:

  • vector是一个古老的集合,通常建议使用arraylist;
  • ArrayList是线程不安全的,而vector是线Te程安全的;
  • 即使为保证List集合线程安全,也不推荐使用Vector。

 

Map集合

  • map用于保存具有映射关系的数据,因此map集合里保存着两组值,一组值用于保存map里的key;

另外一组用于保存map里的value。

  • map中的key和value都可以是任何引用类型的数据。
  • map中的key不允许重复,即同一个map对象的任何两个key通过equals方法比较返回False.
  • 类似python中的dict()

 

Map接口与HashMap类

HashMap是对Map(接口)的一个经典实现类

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class TestMap {
    public static void main(String[] args) {
        Map<String,Integer> map1 = new HashMap<String,Integer>();
        map1.put("b",1); //添加数据
        map1.put("a",2);
        map1.put("e",2);
        System.out.println(map1); //{a=2, b=1, e=2}

        //根据key取值
        System.out.println(map1.get("b")); //1

        //根据key移除键值对
        map1.remove("e");
        System.out.println(map1); // {a=2, b=1}

        //map集合的长度
        System.out.println(map1.size()); //2

        //判断当前的map集合是否包含指定的key
        System.out.println(map1.containsKey("a")); //true
        //判断当前的map集合是否包含指定的value
        System.out.println(map1.containsValue(2)); //true

//        map1.clear(); //清空集合

        //获取map集合的key集合
        Set<String> keys = map1.keySet();
        System.out.println(keys);//[a, b]

        //获取集合的所有value值
        System.out.println(map1.values()); //[2, 1]

        //遍历map集合,by map.keySet();
        for (String key:keys
             ) {
            System.out.println("key:" + key + ", value: " + map1.get(key));
        }
        //key:a, value: 2
        //key:b, value: 1

        //通过map.entrySet();
        Set<Map.Entry<String, Integer>> entrys = map1.entrySet();
        for (Map.Entry<String, Integer> en : entrys
             ) {
            System.out.println("key:" + en.getKey() + ", value: " + en.getValue());
        }
        //key:a, value: 2
        //key:b, value: 1

        System.out.println("--------------------------------------");
        ///排序
        /// TreeMap,按照key排序
        Map<Integer, String> map2 = new TreeMap<Integer, String>();
        map2.put(4,"a");
        map2.put(5,"a");
        map2.put(3,"a");
        map2.put(1,"a");
        System.out.println(map2); //{1=a, 3=a, 4=a, 5=a}

        //TreeMap的自然排序是字典排序
        Map<String,String> map3 = new TreeMap<String,String>();
        map3.put("b","b");
        map3.put("c","c");
        map3.put("d","d");
        map3.put("a","a");
        map3.put("ab","ab");
        System.out.println(map3); //{a=a, ab=ab, b=b, c=c, d=d}

    }
}

 

 

HashMap&Hashtable

  • 一般使用map集合,不会使用过于复杂对象做key。

工具类Collections

操作集合的工具类

举例:

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

public class TestCollections {
    public static void main(String[] args) {
        List<String> lista = new ArrayList<String>();
        lista.add("b");
        lista.add("cd");
        lista.add("ca");
        lista.add("a");
        lista.add("1");

        System.out.println(lista); //[b, cd, ca, a, 1]
        Collections.reverse(lista);
        System.out.println(lista); //[1, a, ca, cd, b]

        //对list集合元素进行随机排序
        Collections.shuffle(lista);
        System.out.println(lista); //[a, 1, cd, b, ca]

        // list集合字典升序
        Collections.sort(lista);
        System.out.println(lista); //[1, a, b, ca, cd]

        //swap交换元素
        Collections.swap(lista,0,4);
        System.out.println(lista); //[cd, a, b, ca, 1]

        System.out.println("----------查找、替换----------------");
        System.out.println(Collections.max(lista)); //cd
        System.out.println(Collections.min(lista)); //1

        //返回指定集合中指定元素的出现次数
        System.out.println(Collections.frequency(lista, "a")); // 1

        //使用新值替换List对象的所有旧值
        Collections.replaceAll(lista,"a","aa");
        System.out.println(lista); //[cd, aa, b, ca, 1]
    }
}

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Student implements Comparator<Student> {
    int age;
    String name;

    public Student(){

    }

    public Student(int age, String name){
        this.age = age;
        this.name = name;
    }

    @Override
    //根据年龄升序排序对象
    public int compare(Student o1, Student o2) {
        if (o1.age > o2.age){
            return 1;
        }else if (o1.age < o2.age){
            return -1;
        }else{
            return 0;
        }
    }

    public static void main(String[] args) {
        Student s1 = new Student(12,"a");
        Student s2 = new Student(12,"abbb");
        Student s3 = new Student(19,"cc");
        Student s4 = new Student(17,"dd");

        List<Student> stus = new ArrayList<Student>();
        stus.add(s1);
        stus.add(s2);
        stus.add(s3);
        stus.add(s4);

        for (Student stu : stus
             ) {
            System.out.println(stu.name + "," + stu.age);
        }
        //a,12
        //abbb,12
        //cc,19
        //dd,17

        Collections.sort(stus, new Student());
        System.out.println("________________________");
        for (Student stu : stus
        ) {
            System.out.println(stu.name + "," + stu.age);
        }
        //a,12
        //abbb,12
        //dd,17
        //cc,19

        System.out.println("---------------------------");
        Student s = Collections.max(stus, new Student());
        System.out.println(s.name + "," + s.age); //cc,19

        Student ss = Collections.min(stus, new Student());
        System.out.println(ss.name + "," + ss.age); //a,12


    }
}

 

 

 

 同步控制

 

 

 

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值