开发环境
JRE:java runtime environment
jre=jvm +类库
JDK:java development kit
jdk=jre+开发工具(如编译工具javac.exe )
dos 命令常用 md rd dir cd del(删文件)*,不会用help查
path:应用程序所在路径
set查看所有环境变量
set path 查看
set path =...修改(临时修改)
set path=C:\Program Files (x86)\bin;%path% 在原有的基础上添加
set path=删除
set classpath 类文件运行路径,jvm只到该路径下查找
set classpath;jvm先到该路径下查找,后到当前路径下查找(这么做没意义)
javac编译java文件 生成class文件 java执行class文件(有主函数,可独立运行)
jvm解析class文件并将其加载到内存中 ,解释执行
jvm不跨平台,是由c编写的 针对不同系统有不同jvm
基本内容
标识符:$,字母,数字,不能以数字开头
// /* */ 多种语言都通用,注释不占用字节码文件空间
/** */是java特有的文档注释 @author @version @param @return等 源文件中的注释不会进入字节码文件中
需求 思路 步骤 写在注释中
例:
byte b1=1;
byte b2=2;
byte b3=b1+b2;报错,byte类型变量在赋值时,会检测值是否在范围内,但两个变量相加值不确定。
例:
Inti=3;
I=i++; //i的结果是3 ,相当于,temp=i,i=i+1;i=temp;
逻辑运算符:& | ^ !&& ||(小区别,而且高效)
位运算符(二进制位的运算):& | ^ << 左移(乘2的次幂运算) >> 右移(除2的次幂运算) >>>无符号右移(都补0)
00000111&运算其他的数,相当于取最低的三位
一个数异或同一个数两次,结果还是这个数
三元运算符 ? :
判断:if …if else … if elseif else(是一条语句,能提高效率,减少判断次数)
局部代码块定义局部变量的生存周期,达到优化目的,释放其内存
选择:switch 中case可以无序,执行时先从有效的case语句开始,遇到break或大括号结束 ;byte short int char 1.5枚举 1.7以后有String
循环:while do...while的区别
for循环 for(初始化表达式;循环条件表达式(boolean类型);循环后操作表达式)。计数的变量生存周期有限,节省内存
转义字符 \ 按下回车:r 回车:n 制表符:t(table) b
windows系统中回车符其实是由两个符号组成的 \r\n.
linux中回车符是 \n.
break 用于 switch和循环语句中,当其单独存在时,下面不要定义其他语句
continue用于循环语句中,当其单独存在时,下面不要定义其他语句 两者都跳最近的循环,可以使用标号跳出
在主函数中,main不是标识符,但jvm只识别它,可以定义main函数的重载
变量必须有初始值,作用域在{}中
自动提升 强制转换 数字默认是 int double 注意精度 long:l float:f
void返回值 对应return;且可以省略
函数重载,函数名相同,参数类型或个数不同,与返回类型,修饰符无关
数组
整型数组未初始化,默认值为0
一维数组一旦建立就要确定长度:
定义格式一: int[] arr = new int[5];需要一个容器,但是不明确容器的具体数据
定义格式二: int[] arr = new int[]{1,2,3};
栈内存。
存储的都是局部变量。
而且变量所属的作用域一旦结束,该变量就自动释放。
堆内存。
存储是数组和对象(其实数组就是对象) 凡是new建立在堆中。
特点:
1,每一个实体都有首地址值。
2,堆内存中的每一个变量都有默认初始化值,根据类型的不同而不同。整数是0,小数0.0或者0.0f,booleanfalse char '\u0000'
3,垃圾回收机制。
sop(arr);输出的是类型@哈希值 例:[I@c17164
每个数组有其属性length :arr.length
ArrayIndexOutOfBoundsException:当访问到数组中不存在的角标时,就会发生该异常。
NullPointerException:当引用型变量没有任何实体指向时,还在用其操作实体。就会发生该异常。
二维数组两种定义方式 是否指定一维数组共同长度
格式一:int[][] arr =new int[3][3];
格式二:int[][] arr = new int[3][];
arr[0]=new int[2];
arr[1]=new int[1];
arr[2]=new int[3];
面向对象 java对事物的描述通常只关注两个方面:属性和行为
对象是该类事物实实在在存在的个体
类:事物的描述 对象:该类事物的实例,通过new来创建
Car c=new Car();Car类型的引用变量指向了该类对象
定义类其实就是在定义类中的成员。
成员:成员变量<-->属性,成员函数<-->行为。
成员变量和局部变量的区别:
1,
成员变量定义在类中,整个类中都可以访问。
局部变量定义在函数,语句,局部代码块中,只在所属的区域有效。
2,
成员变量存在于堆内存的对象中。
局部变量存在于栈内存的方法中。
3,
成员变量随着对象的创建而存在,随着对象的消失而消失。
局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
4,
成员变量都有默认初始化值。
局部变量没有默认初始化值。
匿名对象
1.当对象对方法仅进行一次调用的时候,就可以简化成匿名对象。
2.匿名对象可以作为实际参数进行传递。
封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式 例:private,类,框架
构造函数:为对象进行初始化。多个构造函数,用重载的方式 构造函数里实际有有return;语句(结束函数),但没有返回类型;只要定义了构造函数,默认空参的构造函数就没有了
this关键字代表当前对象 主要用于构造函数等,避免了局部变量和成员变量重名问题,其他成员函数使用时也有this
this可以在构造函数中调用其它构造函数!但必须定义在第一行
static修饰符:修饰的成员被所有对象共享;随着类的加载而存在;可以被类名所调用;静态变量数据存储在静态方法区中
静态方法只能访问静态成员或调用静态方法,不能有this,super
静态变量 静态函数
1,静态变量。
当分析对象中所具备的成员变量的值都是相同的。这时这个成员就可以被静态修饰。只要数据在对象中都是不同的,就是对象的特有数据,必须存储在对象中,是非静态的。如果是相同的数据,对象不需要做修改,只需要使用即可,不需要存储在对象中,定义成静态的。
2,静态函数。
函数是否用静态修饰,就参考一点,就是该函数功能是否有访问到对象中的特有数据。简单点说,从源代码看,该功能是否需要访问非静态的成员变量,如果需要,该功能就是非静态的。如果不需要,就可以将该功能定义成静态的。当然,也可以定义成非静态,但是非静态需要被对象调用,而仅创建对象调用非静态的没有访问特有数据的方法,该对象的创建是没有意义。
静态代码块:随着类的加载而执行,给类进行初始化,只执行一次
构造代码块 :可以给所有对象进行初始化
构造函数:给特定的对象进行针对性初始化
工具类里面的方法都是静态的,所以该类是不需要创建对象的,将构造函数私有化
文档注释提取:javadoc.exe
继承:extends
java支持单继承,不直接支持多继承,通过 “多实现”来体现
什么时候定义继承呢?
当类与类之间存在着所属关系的时候,就定义继承。xxx是yyy中的一种。 xxx extends yyy
所属关系: is a 关系。
当子父类成员变量同名时,用super区分父类
子类不能直接访问父类私有内容,可以间接访问super.getXXX
当子父类中出现成员函数一模一样的情况,会运行子类的函数。这种现象,称为覆盖操作。这时函数在子父类中的特性。
函数两个特性:
1,重载。同一个类中。overload
2,覆盖。子类中。覆盖也称为重写,覆写。override
子类方法覆盖父类方法时,子类方法权限要大于父类!
静态只能覆盖静态,或被静态覆盖override
Super可以访问父类被覆盖的方法
什么时候使用覆盖操作?
当对一个类进行子类的扩展时,子类需要保留父类的功能声明,
但是要定义子类中该功能的特有内容时,就使用覆盖操作完成.
子类构造函数中第一行有默认隐式语super(),调用父类空参构造函数
如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用
父类中哪个构造函数。同时子类构造函数中如果使用this调用了本类构造函数时,那么super就没有了,因为super和this都只能定义第一行。所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数访问父类的构造函数。
一个对象实例化过程:
Person p = new Person();
1,JVM会读取指定的路径下的Person.class文件,并加载进内存,
并会先加载Person的父类(如果有直接的父类的情况下).
2,在堆内存中的开辟空间,分配地址。
3,并在对象空间中,对对象中的属性进行默认初始化。
4,调用对应的构造函数进行初始化。
5,在构造函数中,第一行会先到调用父类中构造函数进行初始化。
6,父类初始化完毕后,在对子类的属性进行显示初始化。
7,在进行子类构造函数的特定初始化。
8,初始化完毕后,将地址值赋值给引用变量.
抽象类abstract
抽象类不可以被实例化,因为调用方法没意义
子类必须覆盖抽象类中的抽象方法才可以实例化,否则也会变成抽象类
抽象类中有构造函数,用于子类初始化
abstract不能和private static final关键字共存
接口inferface :特殊的抽象类,所有方法都是抽象的 ;interface来定义,而不是class
全局常量:public static final
抽象方法:public abstract
接口不能被实例化,只能被实现implements,子类必须覆盖接口中的抽象方法才可以实例化,否则也会变成抽象类
类与类:单继承 类与接口:可多实现 接口与接口:可多继承
一个类在继承另一个类的同时,还可以实现多个接口
extends Aimplements B,C
抽象类和接口的异同点:
相同点:
都是不断向上抽取而来的。
不同点:
1,抽象类需要被继承,而且只能单继承。接口需要被实现,而且可以多实现。
2,抽象类中可以定义抽象方法和非抽象方法,子类继承后,可以直接使用非抽象方法。 接口中只能定义抽象方法,必须由子类去实现。
3,抽象类的继承,是is a关系,在定义该体系的基本共性内容。
接口的实现是 like a 关系,在定义体系额外功能。
例:导盲犬,导盲猪
接口广泛应用于多态
多态 :某一类事物的多种存在形态(要存在函数覆盖,没有的话回调普通父类):父类或接口的引用指向其子类对象(代码体现)
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
多态的弊端:
前期定义的内容不能使用(调用)后期子类的特有内容。
多态的前提:
1,必须有关系,继承,实现。
2,要有覆盖。
多态限制了对特有功能的访问,如果需要使用,可以将对象向下转型,instanceof用于判断对象的具体类型
Animal a = newCat(); //自动类型提升,猫对象提升了动物类型。但是特有功能无法s访问。
//作用就是限制对特有功能的访问。
//专业讲:向上转型。将子类型隐藏。就不用使用子类的特有方法。
// a.eat();
//如果还想用具体动物猫的特有功能。
//你可以将该对象进行向下转型。
// Cat c = (Cat)a;//向下转型的目的是为了使用子类中的特有方法。
// c.eat();
// c.catchMouse();
多态-成员变量:编译和运行都参考等号左边(平时不会出现,面试时用)
多态-成员函数:编译看左边 运行看右边
多态-静态函数:编译和运行都参考左边(一般不会用,直接用类名调用)
内部类(嵌套类):可以访问外部类的成员,包括私有成员
外部类要访问内部类必须建立内部类的对象
一般用于类的设计。分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就是还有的事物定义成内部类来描述。
//直接访问外部类中的内部类中的成员。
//Outer.Inner in = new Outer().new Inner();(不常见,一般内部类私有)
//如果内部类是静态的。 相当于一个外部类
// Outer.Inner in =new Outer.Inner();
//如果内部类是静态的,成员是静态的。
// Outer.Inner.function();
如果内部类中定义了静态成员,该内部类也必须是静态的。
因为内部类持有外部类的引用,外部类.this,才能进行访问:Outer.this.num
内部类在局部位置上只能访问局部中被final修饰的局部成员
匿名内部类:内部类的简写格式
前提:必须继承或实现一个外部类或接口
其实就是一个匿名子类对象;格式是
new 父类or接口(){子类内容}
可以作为函数的参数
new Demo(){ };
注意:有父类对象的实例化过程
final修饰符 修饰的类不能被继承;修饰的函数不能被覆盖;修饰的成员变量变成一个常量,通常加上static,变成共享值。
Object:所有类的根类
boolean equals(Object)比较对象是否相等,相当于==。一般用于覆写,根据对象的特有内容,建立判断对象是否相同的依据,并用instanceof进行类型判断
int类型 hashCode 哈希值
getClass 获取当前对象所属的字节码文件对象
getClass.getName
toString 该对象的字符串表示 同getClass().getName() + '@' +Integer.toHexString(hashCode())
通常也重写
(开发时,会存储进日志文件)
异常体系Throwable(可抛性)具有可抛性:不可处理Error(直接修改程序)和可处理的Exception
throws throw ,凡是可以被这两个关键字所操作的类和对象都具备可抛性.
1.编译时被检测异常:exception和子类(除runtimeexception)
2.运行异常:RuntimeException和其子类,编译器并不检测Rutimeexception,不用throws
声明并抛出:throws throw 程序不再执行
捕捉:try catch finally!程序还会继续运行
throw抛出异常后,可以throws给jvm;也可以catch进行捕获。
异常处理的原则:
1,函数内容如果抛出需要检测的异常,那么函数上必须要声明。
否则必须在函数内用trycatch捕捉,否则编译失败。
2,如果调用到了声明异常的函数,要么trycatch要么throws,否则编译失败。
3,什么时候catch,什么时候throws 呢?
功能内容可以解决,用catch。
解决不了,用throws告诉调用者,由调用者解决 。
4,一个功能如果抛出了多个异常,那么调用时,必须有对应多个catch进行针对性的处理。内部又几个需要检测的异常,就抛几个异常,抛出几个,就catch几个。
finally一定会执行,除了system.exit(0),退出jvm
@多catch时,父类catch放最下边
异常的封装:
class NoAddException extends Exception{}
void addData(Data d)throws NoAddException
{
连接数据库
try
{
添加数据。出现异常 SQLException();
}
catch(SQLExceptione)
{
//处理代码。
throw newNoAddException();
}
fianlly
{
关闭数据库。
}
}
@子类覆盖父类,只能抛出父类的异常或子类或子集
@父类没抛出异常,子类也不能抛,只能try
包package:javac -d . 类名.java
包与包之间的类访问,被访问类及其方法必须是public权限。
protected:不同包中的子类可以访问
default:只在本包中有效
public protected default private
同一类中 ok ok ok ok
同一包中 ok ok ok
子类中 ok ok
不同包中 ok
import:导入包 简化类名书写 导入包中的类
jar:java的压缩包,导入后可以直接使用
开启线程,为了代码同时执行,但cpu在不断的切换
进程:通俗的讲,正在进行中的程序
线程:进程中一个负责程序执行的控制单元
jvm启动至少启动了两个线程 执行main函数线程和负责垃圾回收的线程 system.gc()运行垃圾回收器,调用某个给定对象的finalize 方法。
创建线程:
1.继承Thread类,覆盖run方法,创建子类对象,调用start方法开启线程(jvm调用run)
理想状态:cpu一切换,线程瞬间执行完
获得当前执行线程 Thread.currentThread().获取线程名getName()
2.定义类实现Runnable接口,覆盖接口中唯一的run方法;通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类构造函数的参数进行传递;调用线程对象的start方法开启线程。
卖票案例:第一种方式操作同一数据不方便,第二种方式相当于单纯把任务进行了封装
线程安全问题:多个线程操作共享数据;共享数据的代码有多条。
解决思路;
就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程时不可以参与运算的。必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。
1.解决方法同步代码块synchronized(对象){同步代码}:要求:多个线程且用一个锁(obj对象)。但效率降低了,同步外的线程都会判断锁。
同步的前提:同步中必须有多个线程并使用同一把锁,在run外定义好锁!
2.同步函数:锁唯一,是this :调用函数的对象
3.静态的同步函数:锁是该函数所属字节码文件对象 this.getclass 类名.class
同步的前提:多个线程在同一个锁当中
死锁之一:同步代码嵌套;线程池内线程全部冻结
线程间通讯:多个线程在处理同一资源,但任务却不同。 资源一个类 任务多个类,构造函数绑定资源
案例:数据的输入输出
class Resource
{
private Stringname;
private Stringsex;
private booleanflag = false;
publicsynchronized void set(String name,String sex)
{
if(flag)
try{this.wait();}catch(InterruptedExceptione){}
this.name =name;
this.sex =sex;
flag = true;
this.notify();
}
publicsynchronized void out()
{
if(!flag)
try{this.wait();}catch(InterruptedExceptione){}
System.out.println(name+"...+...."+sex);
flag = false;
notify();
}
}
输入
class Input implements Runnable
{
Resource r ;
Input(Resourcer)
{
this.r = r;
}
public voidrun()
{
int x = 0;
while(true)
{
if(x==0)
{
r.set("mike","nan");
}
else
{
r.set("丽丽","女女女女女女");
}
x =(x+1)%2;
}
}
}
//输出
class Output implements Runnable
{
Resource r;
Output(Resourcer)
{
this.r = r;
}
public voidrun()
{
while(true)
{
r.out();
}
}
}
等待唤醒机制:锁调用
wait():让线程处于阻塞状态,存储到线程池中
notify():唤醒线程池中任意一线程
notifyAll():唤醒线程池中的所有线程
这些方法都定义在同步中,必须明确哪个锁的线程
多生产者 多消费者:
while判断标记,解决了线程获取执行权后,是否需要运行;notifyAll解决了本方线程一定会唤醒对方线程
if判断标记,会导致不该运行的线程运行了
notify只唤醒一个线程,如果唤醒本方线程无意义
while+notify会死锁
class Resource
{
private Stringname;
private intcount = 1;
private booleanflag = false;
publicsynchronized void set(String name)//
{
while(flag)
try{this.wait();}catch(InterruptedExceptione){}
this.name =name + count;
count++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);//生产烤鸭1 生产烤鸭2 生产烤鸭3
flag = true;
notifyAll();
}
publicsynchronized void out()// t3
{
while(!flag)
try{this.wait();}catch(InterruptedExceptione){} //t2 t3
System.out.println(Thread.currentThread().getName()+"...消费者........"+this.name);//消费烤鸭1
flag = false;
notifyAll();
}
}
class Producer implements Runnable
{
private Resourcer;
Producer(Resourcer)
{
this.r = r;
}
public voidrun()
{
while(true)
{
r.set("烤鸭");
}
}
}
class Consumer implements Runnable
{
private Resourcer;
Consumer(Resourcer)
{
this.r = r;
}
public voidrun()
{
while(true)
{
r.out();
}
}
}
jdk1.5版本,把锁封装成了对象,接口Lock代替了synchronized代码块或同步函数 ,同步代码块对锁的操作是隐式的(获取锁,释放锁),lock() unlock()通常需要定义到finally代码块中, 可以一个锁上加多组监视器
Condition将监视器方法封装,一个lock锁可以有多组监视器 await single singleAll。Condition
将 Object
监视器方法(wait
、notify
和 notifyAll
)分解成截然不同的对象,以便通过将这些对象与任意Lock
实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock
替代了 synchronized
方法和语句的使用,Condition
替代了Object 监视器方法的使用。
wait 和 sleep 区别?
1,wait可以指定时间也可以不指定。
sleep必须指定时间。
2,在同步中时,对cpu的执行权和锁的处理不同。
wait:释放执行权,释放锁。
sleep:释放执行权,不释放锁。
停止线程:
1,stop方法。
2,run方法结束。
怎么控制线程的任务结束呢?
任务中都会有循环结构,只要控制住循环就可以结束任务。控制循环通常就用定义标记来完成。但是如果线程处于了冻结状态,无法读取标记。如何结束呢?
可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。
当时强制动作会发生了InterruptedException,记得要处理
守护线程setDaemon():前台线程都退出了,守护线程不管处于什么状态都会强制退出,其定义在开启线程之前
join():线程加入进来,运行
setPriority(int newPriority)更改线程优先级
static int | MAX_PRIORITY |
static int | MIN_PRIORITY |
static int | NORM_PRIORITY |
String类:
字符串对象一旦初始化就不会被改变
String s="asd";存于字符串常量池中
String s1=new String("asd");相当于在堆创建了两个对象,一个new,一个字符串对象,但两者哈希值相等
@对equals方法进行覆写,比较内容,不比较地址
其构造函数中参数可以是字节数组和字符数组,也可以将其一部分变成字符串。
byte[] arr = {97,66,67,68};
String s1 = new String(arr);
System.out.println("s1="+s1);//aBCD
1.获取信息,角标从0开始
length()获取字符串长度
charAt(int index)根据位置获取字符
indexOf没找到,返回-1
indexOf(int ch) 字符在字符串中的位置 参数传‘a’或97都可以
indexOf(int ch,int fromIndex) 从指定位置开始索引
indexOf(String str)
indexOf(String str,int fromIndex)
lastIndexOf也有四个,从后向前找
获取字符串中子串.
String substring(int beginIndex, int endIndex)//包含begin 不包含end 。取到endIndex-beginIndex个字符
String substring(int beginIndex);
2,转换。
2.1 将字符串变成字符串数组(字符串的切割) String[] split(String regex):涉及到正则表达式.
2.2 将字符串变成字符数组。 char[] toCharArray();
2.3 将字符串变成字节数组。
byte[] getBytes();
s = "ab你";
byte[] bytes = s.getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.println(bytes[i]);
}//97 98 -60 -29 英文字母占1个字节,中文占2个字节
2.4 将字符串中的字母转成大小写。
String toUpperCase():大写
String toLowerCase():小写
2.5 将字符串中的内容进行替换
String replace(char oldch,char newch);
String replace(String s1,String s2);
2.6 将字符串两端的空格去除。 String trim();
2.7 将字符串进行连接 。 String concat(string);
3,判断
3.1 两个字符串内容是否相同啊? boolean 猴子equals(Object obj);
boolean equalsIgnoreCase(string str);忽略大写比较字符串内容。
3.2 字符串中是否包含指定字符串? boolean contains(string str);
3.3 字符串是否以指定字符串开头。是否以指定字符串结尾。 boolean startsWith(string); boolean endsWith(string);
4,比较。
int compareTo 0表示相同 正数表示大于 负数小于 返回当前比较字符的差值
例题:一个子串在整串中出现的次数。
public staticint getKeyStringCount_2(String str, String key) {
int count =0;
int index =0;
while((index= str.indexOf(key,index))!=-1){
index =index + key.length();
count++;
}
return count;
}
StringBuffer StringBuilder
StringBuffer:就是字符串缓冲区。
* 用于存储数据的容器。
* 特点:
1,长度是可变的。
2,可以存储不同类型数据。
3,最终要转成字符串进行使用。 toString
4,可以对字符串进行修改。
StringBuffer() StringBuffeer sb = new StringBuffer(); 容量不够,重新创建一个数组,将内容复制到新的数组里面,变成32个字符长度。 |
既然是一个容器对象。应该具备什么功能呢?
* 1,添加: * StringBuffer append(data);
* StringBuffer insert(index,data);
* 2,删除: * StringBuffer delete(start,end):包含头,不包含尾。 * StringBuffer deleteCharAt(int index):删除指定位置的元素 *
3,查找: * char charAt(index); * int indexOf(string); * int lastIndexOf(string);
* 4,修改: * StringBuffer replace(start,end,string); * void setCharAt(index,char);
reverse反转
前者线程同步,线程安全的,用于多线程
后者线程不同步,速度快,提高效率,用于单线程。但最终必须转换成字符串才可以用。
基本数据类型对象包装类。
* 为了方便操作基本数据类型值,将其封装成了对象,在对象中定义了属性和行为丰富了该数据的操作。
* 用于描述该对象的类就称为基本数据类型对象包装类。
*
* byte Byte
* short Short
* int Integer
* long Long
* float Float
* double Double
* char Character
* boolean Boolean
*
* 该包装对象主要用基本类型和字符串之间的转换。
*
* 基本类型--->字符串
* 1,基本类型数值+""
* 2,用String类中的静态方法valueOf(基本类型数值);
* 3,用Integer的静态方法valueO(基本类型数值);
*
* 字符串--->基本类型
* 1,使用包装类中的静态方法 xxx parseXxx("xxx类型的字符串");*****
* int parseInt("intstring");
* long parseLong("longstring");
* boolean parseBoolean("booleanstring");
* 只有Character没有parse方法
* 2,如果字符串被Integer进行对象的封装。
* 可使用另一个非静态的方法,intValue();
* 将一个Integer对象转成基本数据类型值。
*
*
Integer i = 4;//i = new Integer(4);自动装箱 简化书写。
i = i + 6;// i = new Integer(i.intValue() + 6); //i.intValue() 自动拆箱 */
Integer x = 129;//jdk1.5以后,自动装箱,如果装箱的是一个字节(-128~127),那么该数据会被共享不会重新开辟空间。
集合Connection
集合类的由来:
对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定。
就使用集合容器进行存储。
集合特点:
1,用于存储对象的容器。
2,集合的长度是可变的。
3,集合中不可以存储基本数据类型值。
集合容器因为内部的数据结构不同,有多种具体容器。
不断的向上抽取,就形成了集合框架。
框架的顶层Collection接口:
Collection的常见方法:
1,添加。
boolean add(Object obj):
boolean addAll(Collection coll):
2,删除。
boolean remove(object obj):
boolean removeAll(Collection coll);
将两个集合中的相同元素从调用removeAll的集合中删除 A=A-B
void clear();集合中所有元素清空
3,判断:
boolean contains(object obj):
boolean containsAll(Colllection coll);
retainAll取交集,保留和制定集合相同的元素。A=A∩B,和removeAll功能相反
boolean isEmpty():判断集合中是否有元素。
4,获取:
int size():获取长度
Iterator iterator():取出集合中元素的方式:迭代器。
该对象必须依赖于具体容器,因为每一个容器的数据结构都不同。
所以该迭代器对象是在容器中进行内部实现的。
对于使用容器者而言,具体的实现不重要,只要通过容器获取到该实现的迭代器的对象即可,也就是iterator方法。
Iterator接口就是对所有的Collection容器进行元素取出的公共接口。
boolean | hasNext() |
next() | |
void | remove() |
5,其他:
boolean retainAll(Collection coll);取交集。
Object[] toArray():将集合转成数组。
ArrayList的contains和remove都是按着对象的equals()方法进行判定的。通常对类的equals覆写
hashset是根据hashcode 和equals
-------------------------------------------------------------
Collection
|--List:有序(存入和取出的顺序一致),元素都有索引(有0角标),元素可以重复。
|--Set:元素不能重复,无序。
List:特有的常见方法:有一个共性特点就是都可以操作角标。
1,添加
void add(index,element);
void add(index,collection);
2,删除;
Object remove(index):
3,修改:
Object set(index,element); 返回之前的元素
4,获取:
Object get(index);
int indexOf(object);
int lastIndexOf(object);
List subList(from,to);包含头 不包含尾
list集合是可以完成对元素的增删改查。同时List有自己特有的取出元素的方式get()。
List:
:|--Vector:内部是数组数据结构,是同步的。增删,查询都很慢!几乎不用。100%延长
|--ArrayList:内部是数组数据结构,是不同步的。替代了Vector。查询的速度快。50%延长
|--LinkedList:内部是链表数据结构,是不同步的。增删元素的速度很快。虽然有编号,使用get时,内部还是链表查询
-------_-----------------------------------------------
LinkedList:
addFirst();
addLast();
jdk1.6
offerFirst();
offerLast();
getFirst();获取但不移除,如果链表为空,抛出NoSuchElementException
getLast();
jdk1.6
peekFirst();获取但不移除,如果链表为空,返回NULL
peekLast();
removeFirst();获取但移除,如果链表为空,抛出NoSuchElementException
removeLast();
jdk1.6
pollFirst();获取但移除,如果链表为空,返回NULL
pollLast();
题外话:装箱:基本数据类型->引用数据类型
拆箱:引用数据类型与基本数据类型进行运算时
大小可变数组:创建一个新数组,将原来数组的数据复制到新数组中来。
在迭代器过程中,不要使用集合操作元素,容易出现异常。可以使用Iterator接口的子接口ListIterator列表迭代器来完成在迭代中对元素进行更多的操作。
ListIterator it = list.listIterator();获取列表迭代器对象
它可以实现在迭代过程中完成对元素的增删改查。
注意:只有list集合具备该迭代功能.
-------------------------/--------------------
Set:元素不可以重复,是无序。
Set接口中的方法和Collection一致。
|--HashSet: 内部数据结构是哈希表 ,是不同步的。
如何保证该集合的元素唯一性呢?
是通过对象的hashCode和equals方法来完成对象唯一性的。
如果对象的hashCode值不同,那么不用判断equals方法,就直接存储到哈希表中。
如果对象的hashCode值相同,那么要再次判断对象的equals方法是否为true。
如果为true,视为相同元素,不存。如果为false,那么视为不同元素,就进行存储。
记住:如果元素要存储到HashSet集合中,必须覆盖hashCode方法和equals方法。
一般情况下,如果定义的类会产生很多对象,比如人,学生,书,通常都需要覆盖equals,hashCode方法。
建立对象判断是否相同的依据。
linkedhashset 唯一 有序
|--TreeSet:可以对Set集合中的元素进行排序。是不同步的。
判断元素唯一性的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。
TreeSet对元素进行排序的方式一:
让元素自身具备比较功能,元素就需要实现Comparable接口。覆盖compareTo方法。
如果不要按照对象中具备的自然顺序进行排序。如果对象中不具备自然顺序。怎么办?
public int compareTo(Object o) {
Person p =(Person)o;
int temp = this.age-p.age;
returntemp==0?this.name.compareTo(p.name):temp;
}
可以使用TreeSet集合第二种排序方式二:
让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。
TreeSet使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法
public interface Comparable<T>此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。
if(this.hashCode()== obj.hashCode() && this.equals(obj))
哈希表确定元素是否相同
1,判断的是两个元素的哈希值是否相同。
如果相同,在判断两个对象的内容是否相同。
2,判断哈希值相同,其实判断的是对象的hashCode的方法。判断内容相同,用的是equals方法。
注意:如果哈希值不同,是不需要判断equals。
-------_--------------------------------------_-------------------
集合的一些技巧:
需要唯一吗?
需要:Set
需要制定顺序:
需要: TreeSet
不需要:HashSet
但是想要一个和存储一致的顺序(有序):LinkedHashSet
不需要:List
需要频繁增删吗?
需要:LinkedList
不需要:ArrayList
如何记录每一个容器的结构和所属体系呢?
看名字!
List
|--ArrayList
|--LinkedList
Set
|--HashSet
|--TreeSet
后缀名就是该集合所属的体系。
前缀名就是该集合的数据结构。
看到array:就要想到数组,就要想到查询快,有角标.
看到link:就要想到链表,就要想到增删快,就要想要 add get remove+frist last的方法
看到hash:就要想到哈希表,就要想到唯一性,就要想到元素需要覆盖hashcode方法和equals方法。
看到tree:就要想到二叉树,就要想要排序,就要想到两个接口Comparable,Comparator 。
而且通常这些常用的集合容器都是不同步的。
============================================
Map:一次添加一对元素。Collection 一次添加一个元素。
-random
Map也称为双列集合,Collection集合称为单列集合。
其实map集合中存储的就是键值对。
map集合中必须保证键的唯一性。
常用方法:
1,添加。
value put(key,value):返回前一个和key关联的值,如果没有返回null.
2,删除。
void clear():清空map集合。
value remove(key):根据指定的key翻出这个键值对。
3,判断。
boolean containsKey(key):
boolean containsValue(value):
boolean isEmpty();
4,获取。
value get(key):通过键获取值,如果没有该键返回null。
当然可以通过返回null,来判断是否包含指定键。
int size(): 获取键值对的个数。
取出map中的所有元素。
方法一:通过keySet方法获取map中所有的键所在的Set集合,在通过Set的迭代器获取到每一个键,
在对每一个键通过map集合的get方法获取其对应的值即可。
Set<Integer>keySet = map.keySet();
Iterator<Integer>it = keySet.iterator();
while(it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(key+":"+value);}
方法二:通过Map转成set就可以迭代。
找到了另一个方法。entrySet。
该方法将键和值的映射关系作为对象存储到了Set集合中,而这个映射关系的类型就是Map.Entry类型(结婚证)
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Map.Entry<Integer,String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Integer,String> me = it.next();
Integer key= me.getKey();
Stringvalue = me.getValue();
System.out.println(key+"::::"+value);
}
Map常用的子类:
|--Hashtable :内部结构是哈希表,是同步的。不允许null作为键,null作为值。
|--Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合。
|--HashMap : 内部结构是哈希表,不是同步的。允许null作为键,null作为值。
|--TreeMap : 内部结构是二叉树,不是同步的。可以对Map集合中的键进行排序。
泛型:
jdk1.5出现的安全机制。
好处:
1,将运行时期的问题ClassCastException转到了编译时期。
2,避免了强制转换的麻烦。
<>:什么时候用?当操作的引用数据类型不确定的时候。就使用<>。将要操作的引用数据类型传入即可.
其实<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。为什么擦除呢?因为为了兼容运行的类加载器。
泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。
泛型的通配符:? 未知类型。
泛型的限定:
? extends E: 接收E类型或者E的子类型对象。上限
一般存储对象的时候用。比如 添加元素 addAll.
? super E: 接收E类型或者E的父类型对象。 下限。
一般取出对象的时候用。比如比较器。
设计模式:
设计模式:对问题行之有效的解决方式。其实它是一种思想。
单例设计模式。
解决的问题:就是可以保证一个类在内存中的对象唯一性。
必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性。
如何保证对象唯一性呢?
1,不允许其他程序用new创建该类对象。
2,在该类创建一个本类实例。
3,对外提供一个方法让其他程序可以获取该对象。
步骤:
1,私有化该类构造函数。
2,通过new在本类中创建一个本类对象。
3,定义一个公有的方法,将创建的对象返回
//饿汉式
class Single//类一加载,对象就已经存在了。
{
private static final Single s = newSingle();
private Single(){}
public static Single getInstance()
{
return s;
}
}
//懒汉式
class Single2//类加载进来,没有对象,只有调用了getInstance方法时,才会创建对象。
//延迟加载形式。
{
private static Single2 s = null;
private Single2(){}
public static Single2 getInstance()
{
if(s==null)
s = new Single2();
return s;
}
}
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null) //提高效率
{
synchronized(Single.class) //同步
{
if(s==null)
// -->0-->1
s = newSingle();
}
}
return s;
}
}
问题: Java中创建对象的四种方法收藏Java中创建对象的四种方式
1.用new语句创建对象,这是最常见的创建对象的方法。
2.运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
3.调用对象的clone()方法。
4.运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
问题:如何获取父类类名?
Java语言中任何类都是继承自Object类,getClass()方法在Object类中被定义为final与native,子类不能覆盖该方法。因此this.getClass()和super.getClass()最终都调用的是Object中的getClass()方法。而Object的getClass()方法的释义是:返回此Object的运行时类。
可以通过Java的反射机制,使用getClass().getSuperclass().getName()方法来实现
知识:
Final指的是引用的不可变形,即它只能指向初始时指向的那个对象,而不关心指向对象内容的变化
知识:
不可变类是指当创建了这个类的实例后,就不允许修改它的值了,所有基本类型的包装类都是不可变类,String也是不可变类
例题:
public static voidchangeStringBuffer(StringBuffer ss1,StringBuffer ss2){
ss1.append(“hello”);
ss2=ss1;
}
在传递参数时相当于传递了两个地址,在调用append()时,修改了这个地址所指向字符串的值,而在调用ss2=ss1时,相当于修改了函数内部局部变量ss2,与实参没有关系。
知识:
在Java中,char默认使用Unicode编码方式,即每个字符占两个字节。虽然String是由char所组成的,但是它采用了一种更加灵活的方式来存储,即英文占一个字节,中文占两个字节。
知识:
1.finally块中有return语句时,将会覆盖其它renturn语句
2.对于基本数据类型的数据,在finaly块中改变return的值对返回值没有影响。
而对引用类型的数据会有影响。因为程序在执行到return时会首先将返回值存储在一个指定的位置,其次去执行finally,最后再返回
知识:
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁。分配给它的内存会被回收),Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!
知识:
在JAVA中堆被分为两块区域:新生代(young)、老年代(old)。