java基础第十三篇之Collection

常见的几种数据结构:

* 1.堆栈:先进后出

* 2.队列:先进先出

* 3.数组:查找快,增删慢

* 4.链表:查找慢,增删快

import java.util.LinkedList;

/*

* java集合的根接口 Collection

*         共性的方法:增删改查

*         增:add(E e);//addAll(Collection c)

*         删:remove(Object obj);

*         改:无

*         查:size()

*         其他:toArray();clear();isEmpty();

*

* 分为两个子接口:List,Set

* 1.List:接口,有实现类:ArrayList,LinkedList,Vector

*         特点:a.有序的,(这里的有序 不是指123,或者abc这种自然顺序,指的存和取的顺序一致)

*             b.有索引(有下标)

*             c.元素可重复

*         List接口中定义方法:增删改查

*             增加: add(E e);add(int index,E e);//在指定下标处增加一个元素

*             删除: remove(Object obj); remove(int index);//删除指定下标元素

*             修改: set(int index,E e);//把指定下标元素改为新的元素

*             查询: get(int index);//获取指定下标的元素

*         List接口下各种实现类的数据结构特点:

*             ArrayList:    内部采用动态数组结构:查找快,增删慢

*             LinkedList: 内部采用双向链表结构:查找慢,增删快

*             Vector:     内部采用数组结构:查找快,增删慢

*             说明:Vector是从JDK1.0 开始有的

*                 Collection集合根接口从JDK1.2开始的

*             ===============================================

*             实际上ArrayList和Vector中基本没有特有的方法,这些实现类的方法基本上都是List中的方法

*             LinkedList特有的方法:

*             第一组:

*             addFirst(E e),addLast(E e);

*             第二组:

*             public E removeFirst();//返回并删除首元素

*             public E removeLast();

*             第三组:

*             public E getFirst();//返回首元素

*             public E getLast();

*             第四组:

*             public E pop();//出栈,弹栈,就是从集合中删除元素(哪一个:集合首个元素,类似于 removeFirst)

*             public void push(E e);//压栈,就是向集合添加一个元素(添加到集合的第一个,类似于add,addFirst)

*

*

* 2.Set:接口,有实现类,HashSet,LinkedHashSet,TreeSet

*         特点:a.元素不重复

*             b.无索引(无下标)

*             c.无序(有例外,LinkedHashSet,TreeSet)

*         Set接口中定义方法:增删改查(特别好记,Set接口中没有特有方法完全和Collection接口一模一样)

*

*         Set接口下各种实现类的数据结构特点:

*             HashSet: 内部采用哈希表结构

*                     特点:查找较快,增删也较快

*             LinkedHashSet: 内部采用 链表结构+哈希表结构 组合结构

*                     特点:查找较快,增删也较快

*             HashSet和LinkedHashSet特有的方法:无

*                 全部都是和Set接口中一样,和Collection接口中一样

*/

public class LinkedListDemo01 {

public static void main(String[] args) {

// TODO Auto-generated method stub

demo01();

}

/*

* LinkedList特有的方法

*/

public static void demo01(){

//创建一个对象

LinkedList names = new LinkedList();

names.add("jack");

names.add("rose");

names.add("lilei");

names.add("rose");

//添加

//        names.addFirst("hanmeimei");

//        names.addLast("Tom");

//获取(仅仅取出元素,但是不删除)

//        String s1 = names.getFirst();

//        System.out.println(s1);

//        String s2 = names.getLast();

//        System.out.println(s2);

//删除元素(不仅取出元素,而且会在集合中删除)

//        String s1 = names.removeFirst();

//        System.out.println(s1);

//        String s2 = names.removeLast();

//        System.out.println(s2);

//pop 出栈方法

//         String s1 = names.pop();

//         System.out.println(s1);

//         String s2 = names.pop();

//         System.out.println(s2);

//push 入栈方法

names.push("Tom");

names.push("Jirui");

System.out.println(names);

}

}

*

* HashSet 判断元素是否重复是根据两个条件

*

* 1.看新元素的哈希值 和 所有旧元素是否相同,如果不相同那么不重复,存储

*

* 2.如果哈希值相同了,调用equals方法,拿新元素和哈希值相同的那个旧元素,返回值true,那么判断重复元素,不存储

*                             返回值false 判断不重复 可以存储

*

*

* 哈希表:底层是 数组结构+链表结构  特点:查找较快,增删较快        哈希表又称散列表,是一种能将关键字映射成存储地址的记录存储技术。

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,

以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。Hash就是找到一种数据内容和数据存放地址之间的映射关系。

* 对象的哈希值:

*         实际上java中所有的对象 都有一个字符串表示:toString(),默认:包名.类名@哈希值

*         实际上java中所有的对象 都有一个数字的表示:hashCode();//返回的就是一个数字,就是我们说对象的哈希值

*

*

* 字符串的哈希值:

*         字符串类的哈希值 自己重写了hashCode,计算哈希值只跟内容有关系,所有内容相同的字符串,哈希值必定相同

*                                 内容不同的字符串,哈希值还有可能相同

*

*

*

*/

public class StringHashDemo01 {

public static void main(String[] args) {

// TODO Auto-generated method stub

String s1 = new String("重地");

String s2 = new String("通话");

int h1 = s1.hashCode();

int h2 = s2.hashCode();

//System.out.println(h1==h2);

//哈希值是根据地址值计算的,如果String类没有重写hashCode那么算出来的哈希值应该是不一样

//因为String类重写了 hashCode,所以不同的地址和hash值的计算已经没有关系

//System.out.println(s1==s2);//false

System.out.println(h1);//96354

System.out.println(h2);

//        System.out.println(s1);

//        System.out.println(s2);

//我们看了String类的hashCode方法,字符串的哈希值,只跟内容有关系

//可能不可能出现 字符串的内容不同 但是哈希值相同

//比如:"abc"和"acD"

//比如: "重地"和 "通话"

}

/*

* 对象的哈希值

*/

public static void demo01(){

//创建Person对象

Person p1 = new Person();

int hash =  p1.hashCode();

//hash就是p1的哈希值

System.out.println(hash);

System.out.println(p1.toString());

//我们骗了19天,打印对象默认打印出来的不是地址值 是hash值

//哈希值是根据地址值算出来的,怎么算的我们不知道

//实际上 由地址值 计算哈希值 由一个算法计算 散列算法---哈希算法

//在我们java程序中能不能打印出对象 真正的地址值(不能)

//但是地址值 是真正存在的  对象中存储的就是真正的地址值 但是打印的时候打印出来是哈希值

Person p2 = new Person();

int hash2 = p2.hashCode();

System.out.println(hash2);

//不同的对象 地址值肯定不一样,但是哈希值有可能一样吗?

}

}

/*

* 使用HashSet存储自定义的元素:存储Student对象

*

* 我们要求:如果一个学生对象的年龄和姓名都相同,我们不让HashSet存储它

*

* 以后写一个类:

*         1.封装:

*         2.构造(全参和无参)

*         3.toString(方便输出对象)

*         如果这个类还要存储到集合中最好

*         4.hashCode

*         5.euqals

*

*/

public class Student {

private int age;

private String name;

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public Student() {

super();

// TODO Auto-generated constructor stub

}

public Student(int age, String name) {

super();

this.age = age;

this.name = name;

}

@Override

public String toString() {

return "Student [age=" + age + ", name=" + name + "]";

}

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + age;

result = prime * result + ((name == null) ? 0 : name.hashCode());

return result;

}

@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;

Student other = (Student) obj;

if (age != other.age)

return false;

if (name == null) {

if (other.name != null)

return false;

} else if (!name.equals(other.name))

return false;

return true;

}

//自己重写hachCode

// 20 abc

// 20 acD

// 19 acE

//    @Override

//    public int hashCode() {

//        //我们目的,让年龄相同并且名字相同的对象返回的哈希值也相同

//        return this.age * 31 + this.name.hashCode()*49;

//    }

//Eclipse自动生成的hashCode

//自己重写equals方法,让年龄相同,名字相同两个对象调用equals返回值是true

//    @Override

//    public boolean equals(Object obj) {

//        // TODO Auto-generated method stub

//        Student s = (Student)obj;

//        if(this.age != s.getAge()){

//            return false;

//        }

//        if(!this.name.equals(s.getName())){

//            return false;

//        }

//        return true;

//    }

//Eclipse自动生成的equals方法

}

/*

* LinkedHashSet和HashSet的不同点:

* HashSet是无序的

* LinkedHashSet是有序的

*

* contains方法和add方法的原理

*

* 1.如果是ArrayList存储自定义元素 ,那么这个自定义类型 只要重写 equals

*

* 2.如果是HashSet存储自定义元素,那么这个自定义类型 必须重写两个 hashCode,equals

*

*/

/*

* Collection接口:

* add(E e) remove(Object o),size(),toArray();isEmpty();contains()

* 迭代器

*     获取迭代器: Iterator it =  集合对象.iterator();

*     使用迭代器:

*             it.hasNext(); it.next();

*

*    List和Set

*    能够说出List集合特点:有序,索引和重复

*    能够说出Set集合的特点:无索引,不重复,无序的(但是LinkedHashSet,TreeSet是有序的)

*

*    使用List存储的数据结构:ArrayList是数组结构 LinkedList是链表结构

*

*    说出哈希表的特点:数组结构+链表结构: 查找较快,增删较快

*

*    使用HashSet集合存储自定义元素(保证元素的内容相同不能存储)

*        快捷键:alt+shift+s,h

*

*    说出判断集合元素唯一的原理

*        Collection中有contains(Object o);

*        ArrayList中 只调用equals比较

*        HashSet中  调用hashCode 和  equals

*

*        冒泡排序:把一个数组里面的内容 按照从小到大 或者从大到小

*/

public class BubbleDemo {

public static void main(String[] args) {

int[] nums = {7,65,10,532,47,45,234,84,3};

int len = nums.length;

//外层控制趟数

for (int i = 0; i < len-1; i++) {

//里控制次数

for(int j = 0;j < len-1-i;j++){

//nums[j] 和 nums[j+1]

if(nums[j] > nums[j+1]){

int temp = nums[j];

nums[j] = nums[j+1];

nums[j+1] = temp;

}

}

}

for (int i = 0; i < nums.length; i++) {

System.out.println(nums[i]);

}

}

}

冒泡排序优化版:

package com.baidu_01;

import java.util.Arrays;

public class Test3 {

public static void main(String[] args) {

//int[] arr = {1,8,5,3,7,6};

int[] arr = {1,2,3,4,5,6};

boolean b = true ;

for(int i = 0; i < arr.length-1 ; i++) {

//b = true;

for(int j = 0; j < arr.length - 1 -i;j++) {

if(arr[j] > arr[j+1]) {

int temp = arr[j];

arr[j] = arr[j+1];

arr[j+1] = temp;

b = false;

}

}

if(b) {

System.out.println("遍历了一次");

break;

}

}

System.out.println(Arrays.toString(arr));

}

}

3.TreeSet类

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。

TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。向TreeSet中添加的应该是同一个类的对象,且最好是不可变对象。

1.自然排序

自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。

Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。

obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。

如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0

2.定制排序

自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法,该方法用于比较o1和o2的大小:如果该方法返回正整数,则表示o1大于o2

;如果方法返回0,则表示o1等于o2,如果该方法返回负整数,则表示o1小于o2。

Java静态代码块、构造代码块、构造方法的执行顺序 的执行顺序

静态代码优先于非静态的代码,是因为被static修饰的成员都是类成员,会随着JVM加载类的时候加载而执行,而没有被static修饰的成员也被称为实例成员,需要创建对象才会随之加载到堆内存。所以静态的会优先非静态的。

执行构造器(构造方法)的时候,在执行方法体之前存在隐式三步:

1,super语句,可能出现以下三种情况:

1)构造方法体的第一行是this语句,则不会执行隐式三步,

2)构造方法体的第一行是super语句,则调用相应的父类的构造方法,

3)构造方法体的第一行既不是this语句也不是super语句,则隐式调用super(),即其父类的默认构造方法,这也是为什么一个父类通常要提供默认构造方法的原因;

2,初始化非静态变量;

3,构造代码块。

由此可知,构造代码块优先于构造方法的方法体,但是this关键字跟super关键字不能同时出现,而且只能在代码的第一行。如果出现了this关键字,隐式三步就不会执行。

例如,分析下面的代码及执行结果,已经用注释标出了执行步骤Step 1–Step 7。

也就是说,当递归调用多个构造方法的时候,构造代码块只会在最后的(也即方法体第一行不是this语句的)那个构造方法执行之前执行!

public class Test {

public static int a = 0;

static {// Step 1

a = 10;

System.out.println("静态代码块在执行a=" + a);

}

{// Step 4

a = 8;

System.out.println("非静态代码块(构造代码块)在执行a=" + a);

}

public Test() {

this("调用带参构造方法1,a=" + a); // Step 2

System.out.println("无参构造方法在执行a=" + a);// Step 7

}

public Test(String n) {

this(n, "调用带参构造方法2,a=" + a); // Step 3

System.out.println("带参构造方法1在执行a=" + a); // Step 6

}

public Test(String s1, String s2) {

System.out.println(s1 + ";" + s2);// Step 5

}

public static void main(String[] args) {

Test t = null;// JVM加载Test类,静态代码块执行

System.out.println("下面new一个Test实例:");

t = new Test();

}

public boolean contains(Object c) : 判断是否包含元素

public boolean isEmpty() : 判断是否为空

public int size() : 获取集合长度

Collection中主要方法:

boolean add(E e) : 添加元素

boolean remove(Object o) : 删除元素

void clear() : 清空集合

boolean contains(Object o1) : 判断是否包含某元素

boolean isEmpty () : 判断是否为空

int size() : 获取集合长度

}

1

33

执行结果:

静态代码块在执行a=10

下面new一个Test实例:

非静态代码块(构造代码块)在执行a=8

调用带参构造方法1,a=10;调用带参构造方法2,a=10

带参构造方法1在执行a=8

无参构造方法在执行a=8

*/

/*

Arrays : 查API

static void sort(Object[] obj) : 对传进来的基本类型数组进行排序

static void toString(Objec[] a) : 对传入的数组内容以字符串的形式表现出来.

方法重写:字符类出现了一摸一样的方法(注意:返回值类型可以是子父类)

Override和Overload的区别?Overload能改变返回值类型吗?

overload可以改变返回值类型,只看参数列表.

方法重载:本类中出现的方法名一样,参数列表不同的方法,与返回值类型无关.

子类对象调用方法的时候:

先找子类本身,再找父类.

final关键字修饰局部变量:

1.基本类型,是指不能被改变.

2.引用类型,是地址值不能被改变,对象中的属性可以改变

final修饰变量的初始化时:

1.显示初始化;

2.在对象构造完毕前即可

面试:

要求使用已知的变量,在控制台输出30,20,10

class Outer {

public int num = 10;

class Inner {

public int num = 20;

public void show () {

int num = 30;

syso();

syso();

syso();

}

}

}

class InnerClassTest {

public static void main(String[] args ) {

Outer.Inner oi = new Outer().new Inner();

oi.show();

}

}

package , import , class 顺序为:package - import - class 按照这个顺序执行

代码块的概述:在java中,使用{}括起来的代码被称为代码块.

A.代码块分为:局部代码块,构造代码块,静态代码块,同步代码块

代码块应用:

a.局部代码块:在方法中出现;限定变量声明周期,及早释放,提高内存利用率.

b.构造代码块(初始化块) : 在类中方法外出现;多个构造方法中相同的代码块放到一起,每次调用构造都指向,并且在构造方法前指向

c.静态代码块:在类中方法外出现,并加上static 修饰;用于给类进行初始化,在加载的时候就指向,并且只执行一次.

一般用于加载驱动.

多态调用方法这么执行:

成员变量:编译看左边(父类),运行看左边(父类);

成员方法:编译看左边(父类),运行看右边(子类).动态绑定

静态方法:编译看左边(父类),运行看左边(父类);

(静态和类相关,算不上重写,所以,访问换是左边的)

只有非静态方法的成员方法,编译看左边,运行看右边.

内部类访问特点:

外部类访问内部类必须创建对象.

外部类名.内部类名 对象名 = 外部类对象.内部类对象

静态成员内部类:

static :成员内部类被静态修饰后的访问方式是:

外部类名.内部类名 对象名 = 外部类.内部类对象;

面试:

class A {

public void show () {

show2();

}

public void show2() {

syso("我");

}

}

class B extends A{

show(){

show2();

}

show 2 (){

syso("爱")

}

}

class c extends B{

show(){

show2();

}

show 2 (){

syso("你")

}

}

public class Test {

main {

A a = new B();

a.show();

B b = new C();

b.show();

}

}

面试题:

一个抽象类如果没有抽象方法,可不可以订阅为抽象类,?有什么意思?

可以,这么做只有一个目的,就是不让其他类创建本类对象,交给子类完成.

class Test {

public static void main(String[] stgs ) {

//Outer.method().show();

Inter i = Outer.method();

i.show();

}

}

//按照要求补齐代码

interface Inter {

void show();

}

class Outer {

public static Inter method() {

return new Inter() {

public void show() {

syso("show");

}

}

}

}

方法重写注意事项:

1.父类中私有方法不能被重写.(父类私有方法子类根本就无法继承)

2.子类重写父类方法时,访问权限不能更低.

最后就一致

3.父类静态方法,子类也必须通过静态方法进行重写.

其实这个算不算方法重写,但是现象确实如此,至于为什么算不上方法重写

子类重写父类方法,最好声明一摸一样.

例题:

class Fu {

public Person show() {

}

}

class Zi extends Fu {

public Student show() {

}

}

class Person {

}

class Student extends Person {

}

运算符:instanceof : 用法:

是双目运算符,左面的操作是一个对象实例,右面是一个类.当左面的对象是右面的类创建的对象时,该运算符

运算的结果是true,否则是false;

说明:

1.一个类的实例包括本身的实例,以及所有直接或间接子类的实例

2.instanceof左边操作元显示的类型与右边操作元必须是同种类或有继承关系

即位于继承树的同一个分支上,否则会编译出错.

冒泡排序:让数组中的元素,从小到大存储. 

相邻比较思想.                                            我们需要比较多少趟

第一趟:        我们要比较几次 len-1;                    冒泡排序 : 如果一个数组的长度还是len

那么要比较   len-1趟

下标  0-1

//控制躺数

下标  1-2                                            for(int i = 0 ; i < len-1; i ++) {

下标  2-3                                                for(int j = 0 ; j < len-1; j++) {

下标  3-4                                                    比较num3[j]和num3[j+1]

下标  4-5

下标  5-6

}

}

第二趟:

len-1-1;

0-1

1-2

2-3

3-4

4-5

你可能感兴趣的:(java基础第十三篇之Collection)