Java 基础

基本数据类型和运算符

  • byte
  • short
  • int
  • int[]
  • long
  • boolean
  • char
  • char[]
  • float
  • double
  • !
  • %
  • &&
  • ||
  • +
  • //
  • ++
  • - -

注意点

数据类型 封装类 特点
int Integer int初始化是0,Integer初始化是null。Integer是int的封装类,可以实现和字符串的转换
char Character char初始化是_,Character初始化是null
long Long long初始化是0,Long初始化是null
byte Byte byte初始化是0,Byte初始化是null
short Short short初始化是0,Short初始化是null
float Float float初始化是0.0,Float初始化是null
double Double double初始化是0.0,Double初始化是null
boolean Boolean boolean初始化是false,Boolean初始化是null

PS:泛型定义时也不支持数据类型,只能是类

List<int>就不行,但是List<Integer>可以

装箱和拆箱

在自动装箱的时候,Java虚拟机会自动调用Integer的valueOf方法;
在自动拆箱的时候,Java虚拟机会自动调用Integer的intValue方法。

Byte、Short、Integer、Long、Char这几个装箱类的valueOf()方法是以128位分界线做了缓存的,假如是[-128,127]区间的值是会取缓存里面的引用的,以Integer为例,其valueOf(int i)的源代码为:

1
2
3
4
5
6
7
8
static final int low = -128;
static final int high=127;

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

Integer 在静态代码块中缓存了-128 ~ 127 之间的数字(IntegerCache),范围外的就只能去new了,所以integer在比较这个区间内的地址是相同的

参考路径

http://www.jianshu.com/p/946b3c4a5db6

判断,筛选和循环

  • if
1
2
3
4
5
6
7
8
9
public int say(int word){
int a = word;
if(a == 1){
a = 0;
}else{
a = 2;
}
return a;
}
  • switch
1
2
3
4
5
6
7
8
9
10
switch(a){
case 0:
a = 1;
break;
case 1:
a = 2;
break;
default:
a = 0;
}
  • for
1
2
3
4
5
6
7
8
for(int i = 0;i<10;i++){
System.out.println("我循环啦!");
if(i == 3){
System.out.println("跳出循环");
continue;
}
System.out.println("C要大写!");
}
  • while
1
2
3
4
5
6
7
8
9
10
11
12
13
public void speak(int key){
int a = key;
while(a>0){
a--;
if(a == 5){
System.out.println("跳出循环");
break;
}else if(a == 1){
System.out.println("结束方法");
return;
}
}
}
  • foreach
1
2
3
4
int[] bbs = {1,2,3,4,5};
for(int bb : bbs){
System.out.println(bb);
}
  • do while
1
2
3
4
5
int a = 10;
do{
a--;
System.out.println("循环");
}while(a>3);
  • 5 > 4 ? “y” : “n” 返回的是y

面向对象

  • 思想
    • 万事万物都是对象
    • 每个对象都具有各自的状态特征(也可以称为属性)及行为特征(方法)
    • 比如我们考虑一只狗,那么它的 状态是:名称,品种,颜色 行为:吠叫,摇摆,跑等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Dog{
private String breed;
private int age;
private String color;

public void barking(){
}

public void hungry(){
}

public void sleeping(){
}
}

构造方法

  • 介绍
    • 构造方法是一种特殊的方法
    • 构造方法的方法名必须与类名相同
    • 构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型
    • 构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域
1
2
3
4
5
6
7
8
9
10
public class Puppy{
private String name;

public Puppy(){
}

public Puppy(String name){
this.name = name;
}
}

值引用

java中方法参数传递方式是按值传递。
如果参数是基本类型,传递的是基本类型的字面量值的拷贝。
如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。

参考路径

java到底是值传递还是引用传递?

Clone

clone是对对象进行复制,是一维层面的深拷贝,会产生一个新对象,但是对象里的引用还是指向同一个,方法是native方法,效率高。

注意点

  • clone的对象必须要实现Cloneable接口,不然CloneNotSupportedException异常,clone实现的是浅拷贝,如果要深拷贝,需要重写方法,注意重写后的方法的返回值可以是Object的子类
  • 数组的clone,复制的仅仅是数组中的元素,比如数组中元素为引用类型,那仅仅复制引用。若clone的对象中含有链表,则应单独对链表进行循环复制

arraycopy

System.arraycopy是复制一个数组,也是native方法

二维数组或对象数组

arraycopy 也只能实现浅拷贝,因为java没有二维数组的概念,他是数组的数组,所以arraycopy 拷贝二维数组只能是拷贝引用,arraycopy拷贝对象数组也是只能拷贝引用。arraycopy只要拷贝一维数组的基础类型时才是深拷贝

HashCode

hashcode和equal的区别

hashcode能大概区分是否是同一对象,equal是能准确区别对象
hashcode不同,则两个对象不同
hashcode相同,则对象不一定相同,需要进一步equal比较

注意点

  • 设计hashCode()时最重要的因素就是:无论何时,对同一个对象调用hashCode()都应该产生同样的值。如果在讲一个对象用put()添加进HashMap时产生一个hashCdoe值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码
  • 重写equal方法后,一定也要重写hashcode,否则不能使用hashmap了

分装类实现

我会基本列举下面封装类的所有构造方法

在String类中的hashCode是根据String类中包含的字符串获取的,根据哈希算法获取到一个哈希码,那么只要我的字符内容是相等的,我的哈希码也是相同的。

new String(“”)和直接赋值的区别,在于new String(“”)创建两个String对象,直接赋值创建一个

更多区别参考:String和New String()的区别String s=new String()与String s = “”的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {  
String a = "cx";
String aa = "cx"
String b = new String("cx");
char[] p = {'a','b'};
String c = new String(p);
int[] i = {97,98};
String d = new String(i,0,2);
System.out.println(b.hashCode()==a.hashCode());
System.out.println(d.hashCode()==c.hashCode());
System.out.println(a == b);
System.out.println(a == aa);
}
//true
//true
//false 两个对象的内存地址是不同的
//true 引用的常量池字符串的地址是相同的

Integer类中的hashCode和String是一样的,也是根据类中包含的值去生成的哈希码。两个相同大小的integer值,那么它的hashCode也是相等的。这里不用考虑127这个分界线

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {  
Integer a = new Integer(1234);
Integer b = new Integer(1234);
Integer c = new Integer("1234");
Integer d = new Integer("1234");
System.out.println(b.hashCode()==a.hashCode());
System.out.println(d.hashCode()==c.hashCode());
}
//true
//true

Character类也是一样的

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
Character a = new Character('a');
Character b = 'a';
char c = 'a';
char d = 97;
//基本类型没有hashcode方法
System.out.println(b.hashCode()==a.hashCode());
}
//true

Object类中的hashCode则和之前的不一样了,他是根据对象的内存地址经过哈希算法之后获取到的哈希码,由于每个对象的内存地址不相同,所以hashCode是不同的。

toString

是指把对象转成字符串的方法。

  • 当使用+的时候
  • 用println方法的时候

注意

不要在toString方法中用‘+this’这种操作,这样会不断调用toString方法,导致死循环

速学路径

http://www.voidcn.com/blog/u012413167/article/p-5978865.html

继承

  • 介绍
    • 继承一个类,子类会获得父类的所有成员变量和成员方法
    • 一个类只能继承一个父类,但是可以被多个子类继承
1
2
3
4
5
6
7
public class Animal {
public int age = 40;

public int getAge(){
return age;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Dog extends Animal {
public int age = 18;
public String name = "dog";

@Override
public int getAge() {
return age;
}

public void setName(String name){
this.name = name;
}

public String getName(){
return name;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Test{
public static void main(String args[]){
Dog d1 = new Dog();
System.out.println(d1.getName());

//把父类实例赋给子类变量——相当于说动物是狗
//把子类实例赋给父类变量——相当于说狗是动物

Dog d2 = new Animal(); //变量其实只是给你的实例起个名字而已,这里类型转化后,还是Animal类型
d2.setName(30); //程序报错,因为d2的类型还是Animal,Animal没有setName的方法

//父类对象由子类实例化
Animal animal = new Dog();
System.out.println(animal.age);
System.out.println(animal.getAge());
//System.out.println(animal.getName()); 错误,Animal没有getName的方法
}
}
1
2
3
4
结果:   //animal变量访问变量是看 声明的类型,访问方法是看 实例的方法!
dog
40
18
  • instanceof 运算符
    • 左面的对象是右面的类创建的对象时,该运算符运算的结果是true,否则是false
    • instanceof左边操作元显式声明的类型与右边操作元必须是同种类或右边是左边父类的继承关系
1
2
3
4
5
6
7
8
9
10
public class Test{
public static void main(String args[]){

Animal a = new Animal();
Dog d = new Dog();

System.out.println(a instanceof Animal);
System.out.println(d instanceof Animal);
}
}
1
2
3
结果:
true
true
  • 重写
    • 在Java中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改,这就需要采用方法的重写。方法重写又称方法覆盖。

向上转型&向下转型

向上转型:子类引用的对象转换为父类类型称为向上转型。通俗地说就是是将子类对象转为父类对象。此处父类对象可以是接口

向下转型:父类引用的对象转换为子类类型称为向下转型。

前者是一个向上转型,Animal dog 引用指向new Dog();子类对象当成父类对象,只能调用父类的成员,如果子类重写了父类的方法就根据这个引用指向调用子类重写的这个方法(这个方法就是覆盖override)。这个调用过程就称为“动态绑定”。

在向下转型过程中,分为两种情况:

  • 如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
  • 如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。

Java向上转型和向下转型

修饰词

类型 同类 同包 不同包子类 不同包非子类
private yes
default yes yes
protected yes yes yes
public yes yes yes yes
  • private
    • 除了class自己之外,任何人都不可以直接使用
  • default
    • 类可以访问在同一个包中的其他类(朋友)的成员
  • protected
    • 只有相同的包下的类(朋友)和自己的子类(子女)才能访问
  • public
    • 该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
  • final
    • final类不能被继承,没有子类,final类中的方法默认是final的
    • final方法不能被子类的方法覆盖,但可以被继承。
    • final成员变量或参数表示常量,只能被赋值一次,赋值后值不再改变。
    • final不能用于修饰构造方法。
  • static
    • static表示“全局”或者“静态”的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块
    • 被static修饰的成员变量和成员方法独立于该类的任何对象,即不需要实例化对象就能用类名.变量(方法)来使用
1
private static final String StaticFinalVar = "aaa";
  • this
    • this是对象,this.成员变量,this.函数(哪个对象调用的,this就代表该对象)
    • 函数的参数与成员变量重名时,赋值语句使用 this.name = name;
    • this(name); 根据this所带的参数判断调用哪个构造函数。
  • super
    • super(); 调用父类构造函数
    • super.成员函数; 调用父类成员函数或变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class test{
private int num;
private char c;

//无参构造函数
public test(){

}

//一个参数的构造函数
public test(int num){
this.num = num;
}

//两个参数的构造函数
public test(int num,char ch){
//这里调用了第一个构造方法,并且必须放在新的构造方法的第一行
this(num);
c = ch;
}

public int getNum(){
return num;
}

public void setNum(int num){
this.num = num;
}

public static void main(String []args) {
test t = new test(8);
System.out.println(t.getNum());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class exam extends test{
private int grade;

public exam(){
super();
}

public exam(int num){
super(num);
}

public int query(int gradeSheet){
//super.num = gradeSheet;
super.setNum(gradeSheet);
return super.getNum();
}

public static void main(String[] args) {
exam e = new exam(3);
System.out.println(e.getNum());

int sheet = 95;
e.query(sheet);
System.out.println(e.getNum());
}
}
1
2
3
运行结果:
3
95

静态代码块

  • static
    • 静态代码块里的使用的变量和方法也必须是static的
    • 静态代码块是在类加载时自动执行的,非静态代码块是在创建对象时自动执行的代码,不创建对象就不会执行该类的非静态代码块
    • 执行顺序:静态代码块——非静态代码块—-构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class StaticBlock {
//静态代码块
static {
System.out.println("静态块");
}
//非静态代码块
{
System.out.println("构造块,在类中定义");
}
//构造函数
public StaticBlock() {
System.out.println("构造方法执行");
}

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

}
1
2
3
4
5
6
运行结果:
静态块
构造块,在类中定义
构造方法执行
构造块,在类中定义
构造方法执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class HelloA {
public HelloA(){//构造函数
System.out.println("A的构造函数");
}
{//构造代码块
System.out.println("A的构造代码块");
}
static {//静态代码块
System.out.println("A的静态代码块");
}
}
public class HelloB extends HelloA{
public HelloB(){//构造函数
System.out.println("B的构造函数");
}
{//构造代码块
System.out.println("B的构造代码块");
}
static {//静态代码块
System.out.println("B的静态代码块");
}
public static void main(String[] args) {
HelloB b=new HelloB();
}
}
运行结果:
A的静态代码块
B的静态代码块
A的构造代码块
A的构造函数
B的构造代码块
B的构造函数
  • 原理
    • 实例化有两个步骤:1、类加载 2、new 对象
    • 一个类在第一次被使用的时候会被类加载,然后在整个应用程序的生命周期当中不会再次被加载了,就加载这一次
    • 因为static{}是在类加载时候被加载的,所以static{}也只会被加载一次
  • 内部类与静态内部类的区别
    • 静态内部类相对与外部类是独立存在的,静态内部类中无法直接访问外部类中变量、方法。如果要访问的话,必须要new一个外部类的对象,使用new出来的对象来访问。但是可以直接访问静态的变量、调用静态的方法
    • 普通内部类作为外部类一个成员而存在,在普通内部类中可以直接访问外部类属性,调用外部类的方法
    • 如果外部类要访问内部类的属性或者调用内部类的方法,必须要创建一个内部类的对象,使用该对象访问属性或者调用方法
    • 如果其他的类要访问普通内部类的属性或者调用普通内部类的方法,必须要在外部类中创建一个普通内部类的对象作为一个属性,外同类可以通过该属性调用普通内部类的方法或者访问普通内部类的属性

匿名内部类

匿名内部类不能访问外部类方法中的局部变量,除非变量被声明为final类型 

  1. 这里所说的“匿名内部类”主要是指在其外部类的成员方法内定义,同时完成实例化的类,若其访问该成员方法中的局部变量,局部变量必须要被final修饰。  
  2. 原因是编译程序实现上的困难:内部类对象的生命周期会超过局部变量的生命周期。局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。而内部类对象生命周期与其它类一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才会死亡(被JVM垃圾回收)。所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。  
  3. 如果匿名内部类的对象访问了同一个方法中的局部变量,就要求只要匿名内部类对象还活着,那么栈中的那些它要所访问的局部变量就不能“死亡”。  
  4. 解决方法:匿名内部类对象可以访问同一个方法中被定义为final类型的局部变量。定义为final后,编译程序的实现方法:对于匿名内部类对象要访问的所有final类型局部变量,都拷贝成为该对象中的一个数据成员。这样,即使栈中局部变量已死亡,但被定义为final类型的局部变量的值永远不变,因而匿名内部类对象在局部变量死亡后,照样可以访问final类型的局部变量,因为它自己拷贝了一份,且与原局部变量的值始终一致。  
  5. 最后,Java 8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰。此外,Java 8的λ表达式也与此类似只能访问final外部变量但不要求用final修饰,不过,变量同样不能被重新赋值。

集合

collection

  • Collection (接口)
  • List (接口)
    • ArrayList (实现类)
      • 非线程安全
    • Vector (实现类)
      • 线程安全
1
2
3
4
5
6
List<Object> objectList = new ArrayList<Object>();
Object object1 = new Object();
Object object2 = new Object();
objectList.add(object1);
object2 = objectList.get(0);
objectList.remove(0);
  • Set (接口)
    • HashSet (实现类)
      • 不能有重复的元素
1
2
3
Collection books = new HashSet();
books.add("01");
books.add("02");
  • Iterator (接口)
    • 只能用于Collection的遍历
1
2
3
4
5
Iterator it = books.iterator();
while(it.hasNext()){
String book = (String)it.next();
it.remove();
}

排序函数

  • 实现Comparable接口
  • 重载比较函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/** 
* @author guwh
* @version 创建时间:2011-11-3 上午10:49:36
* 类说明
*/
package com.jabberchina.test;

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

public class SortTest {

public static void main(String[] args) {
List<String> lists = new ArrayList<String>();
List<A> list = new ArrayList<A>();
List<B> listB = new ArrayList<B>();
lists.add("5");
lists.add("2");
lists.add("9");
//lists中的对象String 本身含有compareTo方法,所以可以直接调用sort方法,按自然顺序排序,即升序排序
Collections.sort(lists);

A aa = new A();
aa.setName("aa");
aa.setOrder(1);
A bb = new A();
bb.setName("bb");
bb.setOrder(2);
list.add(bb);
list.add(aa);
//list中的对象A实现Comparable接口
Collections.sort(list);

B ab = new B();
ab.setName("ab");
ab.setOrder("1");
B ba = new B();
ba.setName("ba");
ba.setOrder("2");
listB.add(ba);
listB.add(ab);
//根据Collections.sort重载方法来实现
Collections.sort(listB,new Comparator<B>(){
@Override
public int compare(B b1, B b2) {
return b1.getOrder().compareTo(b2.getOrder());
}

});

System.out.println(lists);
System.out.println(list);
System.out.println(listB);

}
}

class A implements Comparable<A>{
private String name;
private Integer order;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}

public Integer getOrder() {
return order;
}
public void setOrder(Integer order) {
this.order = order;
}
@Override
public String toString() {
return "name is "+name+" order is "+order;
}
@Override
public int compareTo(A a) {
return this.order.compareTo(a.getOrder());
}

}

class B{
private String name;
private String order;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getOrder() {
return order;
}
public void setOrder(String order) {
this.order = order;
}
@Override
public String toString() {
return "name is "+name+" order is "+order;
}
}

打印的结果为:
[2, 5, 9]
[name is aa order is 1, name is bb order is 2]
[name is ab order is 1, name is ba order is 2]

map

  • Map (接口)
    • HashMap (实现类)
1
2
3
4
5
6
7
8
9
10
Map map = new HashMap();
map.put("boy","凯杰");
map.put("girl","青娜");
if(map.containKey("boy")){
String name = map.get("boy");
for(String type : map.keySet()){
name = map.remove(type);
System.out.println(name);
}
}
  • 遍历Map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Test{
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);
}
}
}

接口和抽象类

  • interface
    • 接口是抽象方法的集合。一个类实现一个接口,从而继承接口的抽象方法
    • 不能实例化一个接口
    • 接口不包含任何构造函数
    • 所有在接口中的方法都是抽象的
    • 一个接口可以扩展多个接口
    • 在接口中的每个方法也隐式抽象的,所以abstract关键字不需要
    • 在接口中的方法是隐式公开的,即默认是public,不能写成private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//电脑类
public class Computer {
//定义一个接口类型的成员变量
private ConnectToUsb connectToUsb;

//获得接口对象
public ConnectToUsb getConnectToUsb() {
return connectToUsb;
}
//赋值给接口
public void setConnectToUsb(ConnectToUsb connectToUsb) {
this.connectToUsb = connectToUsb;
}

public void connect() {
//调用接口的方法
connectToUsb.connect();
}
}
1
2
3
4
//USB接口
public interface ConnectToUsb {
public abstract void connect();
}
1
2
3
4
5
6
7
//MP3实现了USB接口的方法
public class MpThree implements ConnectToUsb{
@Override
public void connect() {
System.out.println("MP3 To Connect!");
}
}
1
2
3
4
5
6
7
8
9
10
11
//测试
public class Test {
public static void main(String[] args) {
Computer c = new Computer();
MpThree m = new MpThree();
c.setConnectToUsb(m);
c.connect();
}
}

结果:MP3 To Connect!
  • abstract
    • 如果我们要定义的一个类的时候,没有足够的信息来描述一个具体的对象,还需要其他的具体类来支持
    • 这个时候我们可以考虑使用抽象类。在类定义的前面增加abstract关键字,就表明一个类是抽象类。
    • 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
    • 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//形状父类
public abstract class Shapes {
public int x, y;
public int width, height;
public Shapes(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//计算面积
abstract double getArea();
//计算周长
abstract double getPerimeter();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Circle extends Shapes {
public double r;
public double getArea() {
return (r * r * Math.PI);
}
public double getPerimeter() {
return (2 * Math.PI * r);
}
public Circle(int x, int y, int width, int heigh) {
//调用父类构造函数
super(x, y, width, heigh);
r = (double) width / 2.0;
}
}
  • 区别
    • 接口作用
      • 在业务逻辑设计的时候,可以只关注逻辑,不去写具体实现。等到接口写完后,你完全可以把具体实现交给其他人做,其他人按照你的业务逻辑就能完成。
      • 当知道一件事肯定要多次被做或者将来功能扩展的时候会被做,但是每次做的方法都不一样的时候,你可以写个接口,相当于声明了这个方法,而具体实现可以等用的时候再写,这样可以使代码更加简洁明了。
    • 抽象类作用
      • 多个类把共同的代码片段的抽取出来,做成一个基类。
      • 相同行为,不同代码的成员方法,可以用抽象方法来代替,不去具体实现。
      • 相同的代码,基类可以统一来具体实现了,节约了子类的代码
    • 两者区别
      • 接口更加零散,他专注于概括不同的方法。抽象类更加像一个基类,为不同的子类做一个总的基础。
      • 抽象类是对的抽象,而接口是对行为的抽象

多态

多态是同一个行为具有多个不同表现形式或形态的能力

  • 多态的思想
    • 继承,接口实现
      • 狗是动物,猫是动物,鱼是动物
      • 吃可以是吃饭,吃零食,吃大餐
    • 重载
      • 被重载的方法必须改变参数列表(参数类型不同,或参数个数不同)
      • 或是不同的返回类型,但方法名要一样
      • 可以改变访问修饰符
    • 运算符重载
      • 运算符两边的东西不一样,作用也不一样
  • 示例
    • 例子太多,就不举啦😀

字符类

  • String和char[]
1
2
3
4
5
6
String str = "GG";
char[] bm;
bm = str.toCharArray();
//将 String 字符串 str 转换成数组
str = String.valueOf(bm);
//将 char 数组 bm 转换成字符串
  • String是一个引用类型,不是基本数据类型
  • StringBuffer
    • 线程安全的
  • StringBuilder
    • 线程非安全的,会造成死锁
  • StringBuffer与StringBuilder
    • StringBuilder > StringBuffer
    • 他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了。
    • 如果要操作少量的数据用 = String
    • 如果单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
    • 如果多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
  • StringAPI
1
2
3
4
5
6
7
8
9
10
char charAt(int index) //返回指定索引处的 char 值。
String concat(String str) //将指定字符串连接到此字符串的结尾。
boolean contains(CharSequence s) //当且仅当此字符串包含指定的 char 值序列时,返回 true。
boolean equals(Object anObject) //将此字符串与指定的对象比较。
int indexOf(String str) //返回指定字符在此字符串中第一次出现处的索引(从0开始)。
int lastindexOf(String str) //返回指定字符在此字符串中最后一次出现处的索引。
boolean isEmpty() //当且仅当 length() 为 0 时返回 true。
int length() //返回此字符串的长度。
String replace(char oldChar, char newChar) // 返回一个新的字符串,替换此字符串中出现的所有oldChar
String trim() //返回字符串的副本,忽略前导空白和尾部空白。

枚举类

  • enum
1
2
3
public enum Color {  
RED, GREEN, BLANK, YELLOW
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public enum Signal {
GREEN, YELLOW, RED
}

public class TrafficLight {
Signal color = Signal.RED;

public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public enum Color {
//实例的对象
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);//注意封号
// 成员变量
private String name;
private int index;

// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}

// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}

// get set 方法
public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getIndex() {
return index;
}

public void setIndex(int index) {
this.index = index;
}
}
1
2
3
4
5
6
7
public class Main {

public static void main(String[] args) {
Color c = Color.RED;
System.out.println(c.getName());
}
}
1
2
结果:
红色

时间类

  • Date
1
2
3
4
5
6
7
8
9
10
public class Main {
public static void main(String[] args) {
Date d = new Date();
System.out.println(d.getTime()); //1970年到现在的毫秒数
System.out.println(d.getDate()); //今天的日期
System.out.println(d.getDay()); //今天的星期号
System.out.println(d.getHours()); //现在的小时数
······
}
}
1
2
3
4
5
结果:
1477131413252
22
6
18
  • SimpleDateFormat
    • 一个格式化的时间工具类
  • String转Date
1
2
3
4
5
6
7
8
9
10
11
12
public static void main(String[] args) {
try {
String dateString = "2016-10-22 19:43:00";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = df.parse(dateString);
System.out.println(date);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//Sat Oct 22 19:43:00 CST 2016
  • Date转String
1
2
3
4
5
public static void main(String[] args) {
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
System.out.println(time);
}
//2016-10-22 18:25:49

加密类

  • Hash 算法
    • 它的算法的特征是不可逆性,并且在计算的时候所有的数据都参与了运算,其中任何一个数据变化了都会导致计算出来的Hash值完全不同,所以通常用来校验数据是否正确或用作身份验证。
  • MD5
    • 最常用的哈希算法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public String getMD5(String s) {
char hexDigits[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
try {
byte[] btInput = s.getBytes("utf-8");
MessageDigest mdInst = MessageDigest.getInstance("MD5");
mdInst.update(btInput);
byte[] md = mdInst.digest();
int j = md.length;
char str[] = new char[j * 2];
int k = 0;
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
  • SHA
    • SHA加密原理又叫安全哈希加密技术,是当今世界最先进的加密算法
  • MD5和SHA的区别
    • MD5比SHA快,SHA比MD5强度高,更安全
  • salt 盐值
    • 混淆原数据的值