`
sunzhuo
  • 浏览: 3769 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

Java基础学习笔记

阅读更多
java 笔记
(笔记内的图片可另存为然后看大图)
Java基础笔记
path  +;%path%则  接着有 不加就为新的 之前的废弃
path先认当前目录 classpath先认设置目录
classpath如果最后加;分号  则会如果不符合会在当前目录查询
不加分号  只认设置目录 不会在当前目录查询

写程序的时候先写注释 写明思路 需求 方法之类
文档注释后  用javadoc。exe可以形成文档

16进制用0x开头
8进制 用0开头
4个2进制位 是一个16进制位   2进制1111 代表15 再大该进位所以代表16进制
3个2进制位 是一个8进制位    2进制111 代表7 再大该进位所以代表8进制
负数的2进制变现为正数的取反  而且最高位为1  正数最高位为0

float  定义时候 最后要加F 如2.3F  因为默认是double
long  定义时候 最后要加F 如6L  因为默认是int

char2个字符   那为什么不能放2个英文

逻辑运算符
异或
^   true^true  为假  即两边相同为假
&   “与”运算  一边假为假
&&  “双与”  一边为假 即不往下运算  短路
| 与|| 区别  一个为真便为真   一个为真不往下运算 短路
>>右移的时候  最高位补值按照当时的最高位来补  即补值时负数为1 正数为0
>>>这个右移时候  无论 正负都按0来补值
位运算的时候 :
&运算为对2进制值的 逻辑运算   即一边为假即为假 算出2进制的加法值 0为假 1为真
|的运算和&一样
^为异或操作   ~为取反操作
??疑惑????
2进制的负数和正数怎么换算
位运算的时候  异或操作
^操作  a^b^b的话  还是a   所以^可以用来做加密操作  异或后 即为加密在异或回来即为解密

最快判断奇偶数的方法
public static boolean IsEven(int i)
      {
          return (i & 1) == 0;//如果是偶数就返回true
      }
      用关系运算符 

多使用3元运算符
好处: IF esle的简化版
弊端:因为是一个运算符 所以必须的到结果
而if else 写法则不用


如果用switch语句时候 没有加break 则语句完成判断执行成功之后没有加break不跳出接着向下执行
知道碰到大括号  而不管case语句的判断 即case内的语句也会直接执行

switch和if区别
if能完成switch所有的 
switch比if高效  因为直接全部读进内存进行判断 速度快
if语句判断完成往下读取不直接全部读取 速度不如switch快

for(int x=0;x<3:x++){
正确的
}
int x=0;
for(;x<3:){
x++;
也是正确的
}

for循环可以加名称以用来区分
a:for(int x=0;x<3:x++){
外层
b:for(int x=0;x<3:x++){
内层
break a;
}
}

continue 功能作用是
for(int x=0;x<3:x++){
continue 继续执行()内内容结束这次循环 下面的补执行
下面的代码不执行
可以在continue 加if判断来完成循环内的选择性执行或者嵌套循环
加名称来继续别的循环 continue a;
}

直接打印数组而不去遍历来取出所有值的话 会打印为[I@数组地址

功能相同的函数要用相同的名字 以重载形式存在

for循环要灵活运用 从小往大++ 也可以从大到小-- 看那个更高效

面向对象3个特征 封装 继承 多态
以后开发 其实就是找对象使用 没有对象就创建一个对象
找对象 建立对象 使用对象 维护对象的关系。

构造代码块{} 优先于构造函数 给对象初始化用的  适合用于执行每个构造函数都通有的下面的执行函数。

stactic  用于定义共享数据   定义之后 大家都能用。
static特点:
1,随着类的加载而加载。
   也就说:静态会随着类的消失而消失。说明它的生命周期最长。

2,优先于的对象存在
明确一点:静态是先存在。对象是后存在的。

3,被所有对象所共享
4,可以直接被类名所调用。

静态使用注意事项:
1,静态方法只能访问静态成员。
非静态方法既可以访问静态也可以访问非静态。
2,静态方法中不可以定义this,super关键字。
因为静态优先于对象存在。所以静态方法中不可以出现this。
3,主函数是静态的。



静态有利有弊
利处:对对象的共享数据进行单独空间的存储,节省空间。没有必要每一个对象中都存储一份(这是关键 所以那些接口类的函数都是static静态类型的)。
可以直接被类名调用。
弊端:生命周期过长。
访问出现局限性。(静态虽好,只能访问静态。)
静态不能访问非静态的方法。因为静态是先存在。非静态是后存在的

private 表示类的私有属性,只可以在类内部访问使用;

写的方法和函数 要加文档注释

静态代码块。
格式:
static
{
静态代码块中的执行语句。
}

特点:随着类的加载而执行,只执行一次,并优先于主函数。因为主函数有名字 需要被虚拟机调用mian主函数名字才执行
用于给类进行初始化的。

/*
Person p = new Person("zhangsan",20);

该句话都做了什么事情?
1,因为new用到了Person.class.所以会先找到Person.class文件并加载到内存中。
2,执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
3,在堆内存中开辟空间,分配内存地址。
4,在堆内存中建立对象的特有属性。并进行默认初始化。即先初始化为默认值 int为0 string为空。。 然后在赋值操作
5,对属性进行显示初始化。
6,对对象进行构造代码块初始化。
7,对对象进行对应的构造函数初始化。
8,将内存地址付给栈内存中的p变量。

*/


/*
这个是先初始化对象。
称为:饿汉式。

Single类一进内存,就已经创建好了对象。
class Single
{
private static Single s = new Single();
private Single(){}
public static Single getInstance()
{
return s;
}
}
*/

//对象是方法被调用时,才初始化,也叫做对象的延时加载。成为:懒汉式。
//Single类进内存,对象还没有存在,只有调用了getInstance方法时,才建立对象。
class Single
{
private static Single s = null;
private Single(){}
public static Single getInstance()
{
if(s==null)
{
synchronized(Single.class)
{
if(s==null)
s = new Single();
}
}
return s;
}
}

//记录原则:定义单例,建议使用饿汉式。

class 
{
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}


写类的时候 要抽取共同部分 让下面的来继承
继承就是这么来的

覆盖:
1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。

2,静态只能覆盖静态。


记住大家:
重载:只看同名函数的参数列表。
重写(覆盖):子父类方法要一模一样。包括返回值类型

final : 最终。作为一个修饰符,
1,可以修饰类,函数,变量。
2,被final修饰的类不可以被继承。为了避免被继承,被子类复写功能。
3,被final修饰的方法不可以被复写。
4,被final修饰的变量是一个常量只能赋值一次,既可以修饰成员变量,有可以修饰局部变量。
当在描述事物时,一些数据的出现值是固定的,那么这时为了增强阅读性,都给这些值起个名字。方便于阅读。
而这个值不需要改变,所以加上final修饰。作为常量:常量的书写规范所有字母都大写,如果由多个单词组成。
单词间通过_连接。
5,定义内部类的话 能直接操作外部类的变量和方法
内部类定义在类中的局部位置上是,只能访问该局部被final修饰的局部变量。
方法中定义的内部类编译之后,也会出现与外部类不同的独自的字节码,他们有各自的成员变量和方法。换句话说就是会出现两个class
//文件。在内存中,类的属性会被分配到栈中的。当调用结束的时候就会退栈,也就是说在内存中这个属性就消失了。内部类也是类,只有在内存中对
//他的引用消失了内部类才会死亡。也就是说局部类的生命周期要比类的局部变量(这里的y变量)的生命周期要长。所以内部类不可能调用类中已经结束
//调用的属性(这里的变量y)。所以要在方法中的变量前加final,当某一属性加此关键词后就成为常量了,而常量的生命周期为程序的整个执行期间。

今天看到,局部内部类要使用局部变量,那么这个局部变量必须是final的
原因是final的使这个局部变量的生命周期超越了这个方法。


我的问题是: final对象的生命周期为什么可以超越定义这个对象的方法?
            

答:这个问题问得好。许多的JAVA书,这个问题都是“含含糊糊”的。
1)所谓“局部内部类”就是在对象的方法成员内部定义的类。而方法中的类,访问同一个方法中的局部变量,是天经地义的。那么为什么要加上一个final呢?
2)原因是:编译程序实现上的困难,难在何处:内部类对象的生命周期会超过局部变量的生命期。为什么?表现在:局部变量的生命期:当该方法被调用时,该方法中的局部变量在栈中被创建(诞生),当方法调用结束时(执行完毕),退栈,这些局部变量全部死亡。而:内部类对象生命期,与其它类一样,当创建一个该局部类对象后,只有没有其它人再引用它时,它才能死亡。完全可能:一个方法已调用结束(局部变量已死亡),但该局部类的对象仍然活着。即:局部类的对象生命期会超过局部变量。
3)退一万步:局部类的对象生命期会超过局部变量又怎样?问题的真正核心是:如果:局部内部类的对象访问同一个方法中的局部变量,是天经地义的,那么:只要局部内部类对象还活着,则:栈中的那些它要访问的局部变量就不能“死亡”(否则:它都死了,还访问个什么呢?),这就是说:局部变量的生命期至少等于或大于局部内部类对象的生命期。而:正是这一点是不可能做到的
4)但是从理论上:局部内部类的对象访问同一个方法中的局部变量,是天经地义的。所以:经过努力,达到一个折中结果:即:局部内部类的对象可以访问同一个方法中的局部变量,只要这个变量被定义为final.那么:为什么定义为final变可以呢?定义为final后,编译程序就好实现了:具体实现方法是:将所有的局部内部类对象要访问的final型局部变量,都成员该内部类对象中的一个数据成员。这样,即使栈中局部变量(含final)已死亡,但由于它是final,其值永不变,因而局部内部类对象在变量死亡后,照样可以访问final型局部变量。归纳上述回答的真正核心是:局部内部类对象中包含有要访问的final型局部变量的一个拷贝,成为它的数据成员。因此,正是在这个意义上,final型局部变量的生命期,超过其方法的一次调用。严格来说,方法调用结束,所有的局部变量(含final)全死亡了。但:局部内部类对象中有final型局部变量的拷贝。

抽象类的特点:
1,抽象方法一定在抽象类中。
2,抽象方法和抽象类都必须被abstract关键字修饰。
3,抽象类不可以用new创建对象。因为调用抽象方法没意义。
4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。
如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
抽象类的方法会强迫继承的子类去复写实现 否则继承则无意义 所以必须要复写

抽象类和一般类没有太大的不同。
该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。
这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。
通过抽象方法来表示。

抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。
抽象类不可以实例化。


特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。
private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。
而抽象方法出现的就是需要被复写。
static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。
可是抽象方法运行没意义。

什么是模版方法呢?
在定义功能时,功能的一部分是确定的,但是有一部分是不确定,而确定的部分在使用不确定的部分,
那么这时就将不确定的部分暴露出去。由该类的子类去完成。
如下
abstract class GetTime
{
public final void getTime()
{
long start = System.currentTimeMillis();

runcode();

long end = System.currentTimeMillis();

System.out.println("毫秒:"+(end-start));
}
public abstract void runcode();

}


class SubTime extends GetTime
{

public void runcode()
{

for(int x=0; x<4000; x++)
{
System.out.print(x);
}
}
}


class  TemplateDemo
{
public static void main(String[] args)
{
//GetTime gt = new GetTime();
SubTime gt = new SubTime();
gt.getTime();
}
}

继承的话 变量不存在覆盖 是随着类走的 多态用的时候 成员变量看左边父类
class Fu
{
int num=4;
void show()
{
System.out.println("showFu");
}
}
class Zi extends Fu
{
int num=5;
void show()
{
System.out.println("showZi");
}
}
class T
{
public static void main(String[] args)
{
Fu f=new Zi();
Zi z=new Zi();
System.out.println(f.num);
System.out.println(z.num);
f.show();
z.show();
}
}

4
5
showZi
showZi

接口定义时,格式特点:
1,接口中常见定义:常量,抽象方法。
2,接口中的成员都有固定修饰符。
常量:public static final
方法:public abstract
记住:接口中的成员都是public的。


接口:是不可以创建对象的,因为有抽象方法。
匿名内部类的实现是隐藏掉了 其实是接口不是实现
例如
new (这个地方隐藏了 因为是匿名了 其是是类名后面import的接口)<类或接口> <类的主体> 这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。
需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。
否则子类是一个抽象类。

接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。

Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。

如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。

如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;

之所以不用在函数声明,是因为不需要让调用者处理。
当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,
对代码进行修正。




自定义异常时:如果该异常的发生,无法在继续进行运算,
就让自定义异常继承RuntimeException。


对于异常分两种:
1,编译时被检测的异常。

2,编译时不被检测的异常(运行时异常。RuntimeException以及其子类)

建模的时候 用名字提炼法 例如 A学生 B学生 则可以提取出学生抽象类

/*
异常在子父类覆盖中的体现;
1,子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法,只能抛出父类的异常或者该异常的子类。
2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。
如果子类方法发生了异常。就必须要进行try处理。绝对不能抛。

*/

finally只有一种情况不会执行。当执行到System.exit(0);fianlly不会执行。

异常的好处:
1,将问题进行封装。
2,将正常流程代码和问题处理代码相分离,方便于阅读。


异常的处理原则:
1,处理方式有两种:try 或者 throws。
2,调用到抛出异常的功能时,抛出几个,就处理几个。
一个try对应多个catch。
3,多个catch,父类的catch放到最下面。
4,catch内,需要定义针对性的处理方式。不要简单的定义printStackTrace,输出语句。
也不要不写。
当捕获到的异常,本功能处理不了时,可以继续在catch中抛出。
try
{
throw new AException();
}
catch (AException e)
{
throw e;
}

如果该异常处理不了,但并不属于该功能出现的异常。
可以将异常转换后,在抛出和该功能相关的异常。

或者异常可以处理,当需要将异常产生的和本功能相关的问题提供出去,
当调用者知道。并处理。也可以将捕获异常处理后,转换新的异常。
try
{
throw new AException();
}
catch (AException e)
{
// 对AException处理。
throw new BException();
}

比如,汇款的例子。


异常的注意事项:
在子父类覆盖时:
1,子类抛出的异常必须是父类的异常的子类或者子集。
2,如果父类或者接口没有异常抛出时,子类覆盖出现异常,只能try不能抛。

多态的好处    把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。

要记住:同步synchroized 使用的前提:
1,必须是两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。
这是才可以称为这些线程被同步了

特殊:字符串和字节数组在转换过程中,是可以指定编码表的。要进行编码转换
操作时候要先转换字节数组 然后指定编码表来进行操作 再转换回来即可。

把功能细小化 不要写一堆在一个函数里


Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。


|--Set:元素是无序,元素不可以重复。、


List:
特有方法。凡是可以操作角标的方法都是该体系特有的方法。


add(index,element);
addAll(index,Collection);


remove(index);


set(index,element);

get(index):
subList(from,to);
listIterator();
int indexOf(obj):获取指定元素的位置。
ListIterator listIterator();





List集合特有的迭代器。ListIterator是Iterator的子接口。

在迭代时,不可以通过集合对象的方法操作集合中的元素。
因为会发生ConcurrentModificationException异常。

所以,在迭代器时,只能用迭代器的放过操作元素,可是Iterator方法是有限的,
只能对元素进行判断,取出,删除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。

该接口只能通过List集合的listIterator方法获取。

instanceof是Java、php的一个二元操作符,和==,>,<是同一类东西。由于它是由字母组成的,所以也是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据。可以用在继承中的子类的实例是否为父类的实现。

示例

  举个例子:
  String s = "I AM an Object!";
  boolean isobject = s instanceof Object;
  我们声明了一个String对象引用,指向一个String对象,然后用instanceof来测试它所指向的对象是否是Object类的一个实例,显然,这是真的,所以返回true,也就是isobject的值为true。
  instanceof有一些用处。比如我们写了一个处理账单的系统,其中有这样三个类:
  public class Bill {//省略细节}
  public class PhoneBill extends Bill {//省略细节}
  public class GasBill extends Bill {//省略细节}
  在处理程序里有一个方法,接受一个Bill类型的对象,计算金额。假设两种账单计算方法不同,而传入的Bill对象可能是两种中的任何一种,所以要用instanceof来判断:
  public double calculate(Bill bill) {
  if (bill instanceof PhoneBill) {
  //计算电话账单
  }
  if (bill instanceof GasBill) {
  //计算燃气账单
  }
  ...
  }
  这样就可以用一个方法处理两种子类。
  然而,这种做法通常被认为是没有好好利用面向对象中的多态性。其实上面的功能要求用方法重载完全可以实现,这是面向对象编程应有的做法,避免回到结构化编程模式。只要提供两个名字和返回值都相同,接受参数类型不同的方法就可以了:
  public double calculate(PhoneBill bill) {
  //计算电话账单
  }
  public double calculate(GasBill bill) {
  //计算燃气账单
  }
  所以,使用instanceof在绝大多数情况下并不是推荐的做法,应当好好利用多态。
  instanceof 一般情况下 用在对象类型的强制转换 ,
  例如:
  继承关系 class Manager extends Employee
  ----------------------------------------------------------
  public void doSomething(Employee e) {
  if ( e instanceof Manager){
  Manager m = (Manager) e ;
  }
  }

List集合判断元素是否相同,依据是元素的equals方法。

涉及到集合的操作  自己写类的时候 要复写hashcode和equals方法 因为
集合操作时候会调用类的这两个方法来分辨存入的值。

|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。

注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。


|--TreeSet:

Set集合的功能和Collection是一致的。

Set:无序,不可以重复元素。
|--HashSet:数据结构是哈希表。线程是非同步的。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。

|--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.

TreeSet排序的第一种方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。

TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。

记住,排序时,当主要条件相同时,一定判断一下次要条件。

TreeSet 可以自定义排序 不是同步的。

Vector 是同步的。

特殊之处:
静态方法不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
public  static <W> void method(W t)
{
System.out.println("method:"+t);
}

? 通配符。也可以理解为占位符。
泛型的限定;
? extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限

Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

当发现有映射关系时,可以选择map集合。
因为map集合中存放就是映射关系。
当数据之间存在这映射关系时,就要先想map集合。

map集合的两种取出方式:
1,Set<k> keySet:keySet()将map中所有的键存入到Set集合。因为set具备迭代器。
所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。


Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。


2,Set<Map.Entry<k,v>> entrySet:entrySet()将map集合中的映射关系存入到了set集合中,
而这个关系的数据类型就是:Map.Entry

Entry其实就是Map中的一个static内部接口。
为什么要定义在内部呢?
因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。
而且该事物在直接访问Map集合中的元素。



/*
StringBuffer是字符串缓冲区。

是一个容器。
特点:
1,长度是可变化的。
2,可以字节操作多个数据类型。
3,最终会通过toString方法变成字符串。



C create U update R read D delete

1,存储。
StringBuffer append():将指定数据作为参数添加到已有数据结尾处。
StringBuffer insert(index,数据):可以将数据插入到指定index位置。


2,删除。
StringBuffer delete(start,end):删除缓冲区中的数据,包含start,不包含end。
StringBuffer deleteCharAt(index):删除指定位置的字符。

3,获取。
char charAt(int index)
int indexOf(String str)
int lastIndexOf(String str)
int length()
String substring(int start, int end)

4,修改。
StringBuffer replace(start,end,string);
void setCharAt(int index, char ch) ;


5,反转。
StringBuffer reverse();

6,
将缓冲区中指定数据存储到指定字符数组中。
void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)


JDK1.5 版本之后出现了StringBuilder.

StringBuffer是线程同步。
StringBuilder是线程不同步。

以后开发,建议使用StringBuilder

升级三个因素:
1,提高效率。
2,简化书写。
3,提高安全性。

*/

Collection
|--List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意,对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
Set集合的功能和Collection是一致的。
Set:无序,不可以重复元素。
|--TreeSet:
|--HashSet:数据结构是哈希表。线程是非同步的。
保证元素唯一性的原理:判断元素的hashCode值是否相同。
如果相同,还会继续判断元素的equals方法,是否为true。

|--TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树。
保证元素唯一性的依据:
compareTo方法return 0.

TreeSet排序的第一种方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。
例如自己创建类 实现接口复写这个方法 这个类就能排序

TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的。
这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。记住,排序时,当主要条件相同时,一定判断一下次要条件
例如String默认有compareTo方法 但是需要比较长度来排序 就自定义comparator()
Map
|--Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低。
|--HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。
|--TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

集合框架的工具类。
Collections:集合框架的工具类。里面定义的都是静态方法。

Collections和Collection有什么区别?
Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。
它有两个常用的子接口,
List:对元素都有定义索引。有序的。可以重复元素。
Set:不可以重复元素。无序。

Collections是集合框架中的一个工具类。该类中的方法都是静态的
提供的方法中有可以对list集合进行排序,二分查找等方法。
通常常用的集合都是线程不安全的。因为要提高效率。
如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。

Arrays:用于操作数组的工具类。
里面都是静态方法。

asList:将数组变成list集合

//把数组变成list集合有什么好处?
/*
可以使用集合的思想和方法来操作数组中的元素。

注意:将数组变成集合,不可以使用集合的增删方法。
因为数组的长度是固定。
contains。
get
indexOf()
subList();

如果你增删。那么会反生UnsupportedOperationException,

如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。

集合变数组。
Collection接口中的toArray方法。
1,指定类型的数组到底要定义多长呢?
当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。
当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。
所以创建一个刚刚好的数组最优。
String[] arr = al.toArray(new String[al.size()]);

2,为什么要将集合变数组?
为了限定对元素的操作。不需要进行增删了。

LinkedList:特有方法:
addFirst();
addLast();

getFirst();
getLast();
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException

removeFirst();
removeLast();
获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException


在JDK1.6出现了替代方法。

offerFirst();
offerLast();


peekFirst();
peekLast();
获取元素,但不删除元素。如果集合中没有元素,会返回null。

pollFirst();
pollLast();
获取元素,但是元素被删除。如果集合中没有元素,会返回null。


高级for循环

格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
{

}

对集合进行遍历。
只能获取集合元素。但是不能对集合进行操作。

迭代器除了遍历,还可以进行remove集合中元素的动作。
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

传统for和高级for有什么区别呢?

高级for有一个局限性。必须有被遍历的目标。

建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义脚标。

StaticImport  静态导入。

当类名重名时,需要指定具体的包名。
当方法重名是,指定具备所属的对象或者类。
import static  java.util.Arrays.*;//导入的是Arrays这个类中的所有静态成员。

Runtime对象
该类并没有提供构造函数。
说明不可以new对象。那么会直接想到该类中的方法都是静态的。
发现该类中还有非静态方法。
说明该类肯定会提供了方法获取本类对象。而且该方法是静态的,并返回值类型是本类类型。

由这个特点可以看出该类使用了单例设计模式完成。
每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。可以通过 getRuntime 方法获取当前运行时。

应用程序不能创建自己的 Runtime 类实例。
Runtime用处
返回Process(进程) exec(String command)
          在单独的进程中执行指定的字符串命令。等功能

查表法:
Calendar c = Calendar.getInstance();


String[] mons = {"一月","二月","三月","四月"
,"五月","六月","七月","八月"
,"九月","十月","十一月","十二月"};


String[] weeks = {
"","星期日","星期一","星期二","星期三","星期四","星期五","星期六",
};
int index = c.get(Calendar.MONTH);

int index1 = c.get(Calendar.DAY_OF_WEEK);

sop(c.get(Calendar.YEAR)+"年");
//sop((c.get(Calendar.MONTH)+1)+"月");
sop(mons[index]);
sop(c.get(Calendar.DAY_OF_MONTH)+"日");
//sop("星期"+c.get(Calendar.DAY_OF_WEEK));
sop(weeks[index1]);


Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。

字节流是2进制的处理方式
字符流是带编码的字节流处理方式
当用到处理文字的时候 涉及到每个国家的文字编码不同 应该用字符流
其他的如图片 电影 里面没有编码信息的应该用字节流

System:类中的方法和属性都是静态的。
out:标准输出,默认是控制台。
in:标准输入,默认是键盘。
描述系统一些信息。
获取系统属性信息:Properties getProperties();

//如何在系统中自定义一些特有信息呢?
System.setProperty("mykey","myvalue");
有这些常见等功能。

Condition接口配合lock使用
lock unlock   
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用

Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

装饰设计模式:
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。
并基于被装饰的对象的功能,提供更强的功能。

扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

目的:OutputStream  Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
但是FileWriter是使用的默认编码表。GBK.

但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream

OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");

需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);

所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,
需要用到转换流。

设置 System.setIn(new FileInputStream("PersonDemo.java"));
System.setOut(new PrintStream("zzz.txt"));
即为改变输入源和输出源  可以当复制粘贴用。
class  TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("PersonDemo.java"));

System.setOut(new PrintStream("zzz.txt"));

//键盘的最常见写法。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));


BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

String line = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}

bufr.close();

}
}

File类的renameTo()可以当剪切用
File f1 = new File("c:\\Test.java");
File f2 = new File("d:\\hahah.java");

sop("rename:"+f2.renameTo(f1));

函数自己调用自己 称之为递归。
递归要注意:
1,限定条件。

2,要注意递归的次数。尽量避免内存溢出。

打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。

字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream



字符打印流: 这个类很厉害的 很实用
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。

枚举的用法

class SequenceDemo
{
public static void main(String[] args) throws IOException
{

Vector<FileInputStream> v = new Vector<FileInputStream>();


v.add(new FileInputStream("c:\\1.txt"));
v.add(new FileInputStream("c:\\2.txt"));
v.add(new FileInputStream("c:\\3.txt"));

Enumeration<FileInputStream> en = v.elements();

SequenceInputStream sis = new SequenceInputStream(en);

FileOutputStream fos = new FileOutputStream("c:\\4.txt");

byte[] buf = new byte[1024];

int len =0;
while((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}

fos.close();
sis.close();

RandomAccessFile

该类不是算是IO体系中子类。
而是直接继承自Object。

但是它是IO包中成员。因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。


其实完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。

如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。
多线程 分段读取写入 这是这个类的高级应用 例如下载等

BeanUtils包可以操作map对象和Javabean对象

arrarylist.add(element);
element.set("lalala");  顺序是被允许的    因为是指针指向的值 所以加入集合后指向的值 仍然是可以变化的。

常见的编码表
"ASCII":美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1 :拉丁码表。欧洲码表用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java 语言使用的就是unicode UTF-8 :最多用三个字节来表示一个字符。是Unicode的一种子类 升级版 还有utf-16

内省是操作已编译的javabean属性的操作方法 是一种关于bean的反射

BeanUtils关于bean的类型自动转换  只能转换8种基本数据类型
可以向上追溯父类的方法  进而赋值  (date.setTime,"XXX")

拿到数据要先判断在操作

Junit:
我们写好一个方法后经常希望对其单独进行测试,从前我们都是写一个main方法,在main方法中对被测试方法进行调用。这种方式相对麻烦。
Junit是一个测试框架,利用它可以在不写main方法的情况下调用被测试方法,从而对方法中的代码进行测试。
要求:
被测试方法必须为无参数、非静态、无返回值的公共(public)方法。
测试用类必须为public类
测试过程:
在方法上加上注解:@Test
导入Junit框架jar包
在被测试方法上执行Junit测试
写测试用例:
@BeforeClass 在被测试类加载后立即执行,必须是静态的方法
@AfterClass 在被测试类释放前执行,必须是静态的方法
@Before 在测试方法执行前执行
@After 在测试方法执行后执行

XML的dtd约束文件 .dtd文件应使用UTF-8或Unicode编码

DOM解析的
Transformer t=TransformerFactory.newInstance().newTransformer();
t.transform(newDOMSource(doc), new StreamResult("XXX.xml"));
是默认用UTF-8输出的 要是有编码转换问题要自己设置编码格式

SAX方式解析DefaultHandler
DefaultHandler是一个类,他默认实现了ContentHandler接口,并提供了其中所有方法的空实现,我们可以自己写一个类继承这个类,复写其中我们需要使用到的方法。


基本数据类型就8种,记住就好了。除了这些都是引用型的了。

java四类八种基本数据类型

第一类:整型 byte short int long
第二类:浮点型 float double

第三类:逻辑型 boolean(它只有两个值可取true false)

第四类:字符型 char

在栈中可以直接分配内存的数据是基本数据类型。
引用数据类型:是数据的引用在栈中,但是他的对象在堆中。
要想学好Java必须知道各种数据的在内存中存储位置。
对内存有了很好的了解,可以有助你分析程序。

public static void main(String[] args){}
args只是名字,可以改写成其他的名字
命令行启动java程序时,可以输入参数
> java YourClass 参数1 参数2 ...
这些参数由虚拟机传给main方法,类型为String数组,这可以让程序每次运行由参数配置,具有一定的动态性。


Java对URL和URI的区分
String
urlString = "http://192.168.21.77:8080/swp/mainPage?aa=11&bb%3D22";
URI uri = URI.create(urlString);
System.out.println(uri.getPath());
System.out.println(uri.getQuery());//解码
URL url2 = new URL(urlString);
System.out.println(url2.getQuery());//不解码

URI可以解码注意,URI 类在某些特定情况下对其组成字段执行转义。建议使用 URI 管理 URL 的编码和解码,并使用 toURI() 和 URI.toURL() 实现这两个类之间的转换。 也可以使用 URLEncoder 和 URLDecoder 类,但是只适用于 HTML 形式的编码,它与 RFC2396 中定义的编码机制不同。
URI是个纯粹的句法结构,用于指定标识Web资源的字符串的各个不同部分。URL是URI的一个特例,它包含了定位Web资源的足够信息。其他URI,比如: mailto:cay@horstman.com 则不属于定位符,因为根据该标识符无法定位任何资源。像这样的URI我们称之为URN(统一资源名称)。 在Java类库中,URI类不包含任何访问资源的方法,它唯一的作用就是解析。相反的是,URL类可以打开一个到达资源的流。因此URL类只能作用于那些Java类库知道该如何处理的模式,例如:http:,https:,ftp:,本地文件系统(file:),和Jar文件(jar:)。 URI类的作用之一是解析标识符并将它们分解成各个不同的组成部分。你可以用以下方法读取它们: getSchema getHost getPort getPath getQuery URI类的另一个作用是处理绝对标识符和相对标识符。如果存在一个如下的绝对URI: http://docs.mycompany.com/api/java/net/serversocket.html 和一个如下的相对URI: ../../java/net/socket.html#Socket() 那么你可以将它们合并成一个绝对URI: http://docs.mycompany.com/api/java/net/socket.html#Socket() 这个过程被称为相对URL的转换。 与此相反的过程成为相对化。例如:假设你有一个基本URI: http://docs.mycompany/api 和另一个URI: http://docs.mycompany/api/java/lang/String.html 那么相对化后的URI就是: java/lang/String.html
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics