java基础学习笔记

接触编程一年多了,也在csdn这个社区潜水了很久,一直都在吸收他人的观点、解决方案,鉴于开源思想,把我学习编程的过程及思想分享出来。

第一次发博客,笔记也有点乱,大佬多多担待。


面向对象

定义在方法中的变量都是局部变量

对象封装成员变量的数据

面向对象的三个特征:

1,封装;1,继承;3,多态

 

封装:隐藏实现细节,对外提供公共的访问方式(接口)

 

封装的体现之一:将属性都私有化,对外提供对应的setxxx getxxx方法来访问。

 

封装的好处:

1,提高安全性,不允许直接访问细节,并通过公共的方式来访问,可以实现可控。

2,提高了易用性。

3,提高了复用性。

4,隔离了变化。

 

 

 

 

 

 

 

 

 

 

 

 

DAY08

设计模式:解决某一种问题的一种思想,是一种行之有效的解决方式。

面向对象有23种模式

 

单例设计模式;

解决的问题:保证一个类的对象在内存中的唯一性。

应用场景;多个程序都在操作同一个配置文件时,需要程序A操作后的结果,

程序B要知道并继续基于A操作后的结果进行操作。

前提,数据都存储在配置文件对象中,要求程序A和程序B操作的配置文件对象是同一个。

 

怎么实现呢?怎么可以保证这个类只能产生一个对象?

 

思路;

1. 问题是其他程序都可以通过new创建该类的对象,无法控制数量。所以,不让其他程序new不就行了吗

2. 那第一步的问题也产生了,那其他程序不就没有对象了吗?干脆,在本类中自己new一个本类对象,这样的好处是,不让别的程序new,自己new,可以实现数量控制。

3. 对外提供让其他程序获取该对象的方式,就行了。

 

步骤:

1, 不让其他程序new该类对象,咋办? 可以将该类的构造函数私有化。

2, 在本类中new一个对象。

3, 定义一个方法返回该对象。让其程序可以获取到,之所以定义访问,就是为了可控,

 

 

继承:

1, 提高了代码的复用性,

2, 让类与类之间产生了关系,为第三个特征多态提供了前提。

 

java支持单继承,不直接支持多继承。

单继承:一个类只能有一个父类。

多继承:一个类可以有多个父类,java并不直接支持。

优势:可以让子类具备更多的功能。

弊端:调用的不确定性,因为方法的主体不同,java对其进行改良。

 

多层次继承:

学习一个继承体系时,先看顶层,了解该体系中的具备的基本功能,

使用时,找体系最下面的对象。

 

什么时候定义继承?

当事物之间存在着所属(isa)关系时,可以通过继承来体现这个关系。

例如:xxx是yyy中一种,xxx  extends  yyy

 

子父类出现后,代码上的一些特点:

1、 成员变量

2、 成员函数

3、 构造函数

 

成员变量,注意的是原理

当子父类中出现了同名的成员变量,用关键字super来区分。

 

super和this的用法很相似。

区别:this代表的是本类的对象引用;

        super代表的是父类的那片空间,

注意:super并不代表对象的引用!

 

子父类的方法的特点:

特殊情况:

当子父类中出现了一模一样的方法时,子类对象运行的是子类的方法,这种特殊情况称之为“override覆盖或着复写、重写”。

覆盖:返回值类型、函数名、参数列表都一致。

 

覆盖使用的注意事项:

1、 子类方法覆盖父类方法,必须要保证权限大于等于父类权限,

2、 静态只能覆盖静态,或者被静态覆盖

 

子父类中构造函数的特点:

创建子类对象时,FU中的空参数构造函数也运行了?

因为子类中所有的构造函数的第一行默认都有一个隐式的super();语句。

调用本类中的构造函数用this(实参列表)语句,调用父类中的构造函数用super(实参列表);

 

为什么子类对象初始化都要访问父类中的构造函数呢?

因为子类继承了父类中的内容,所以创建对象时必须要看父类是如何对内容进行初始化的。

这就是子类的实例化过程。

 

注意:当父类中没有空参数构造函数时,子类需要通过显示定义super语句指定要访问的父类中的构造函数。

注意:用来调用父类构造函数的super语句在子类构造函数中必须定义在第一行,因为父类的初始化要先完成。

 

问题:

1、 this和super用于调用构造函数,可以同时存在吗?

不可以,因为它们只能定义在第一行。

2、 为什么需要定义在第一行?

因为初始化动作要先执行。

 

final关键字,最终。

1、 final修饰符,可以修饰类、方法、变量

2、 final修饰的类不可以被继承;

3、 final修饰的方法不可以被覆盖。

4、 final修饰的变量是一个常量,只能赋值一次

当使用的数据不变时,需要定义阅读性强的名称来表示该数据,并将该数据final化,被final修饰的变量,名称规范是:所有字母都大写,如果由多个单词组成,需要通过_进行分隔

 

DAY09

描述一个事物,却没有足够信息,这时候就将这个事物称为抽象事物。

abstract class 抽象类

abstract void 抽象函数

 

面对抽象的事物,虽然不具体,但是可以简单化

不用面对具体的事物。

 

特点:

1、 抽象方法一定定义在抽象类中,都需要用abstract来修饰,

2、 抽象类不能实例化,不能用new关键字创建对象。

3、 只有子类覆盖了所有的抽象方法后,子类具体化,子类就可以创建对象,如果没有覆盖所有的抽象方法,那么子类还是一个抽象类。

 

抽象类也是不断的向上抽取而来的,抽取了方法的声明而不确定具体的方法内容,由不同的子类来完成具体的方法内容。

 

问题:

1、 抽象类中有构造函数吗?

有,抽象类的构造函数虽然不能给抽象类对象实例化,因为抽象类不能创建对象,但是抽象类有子类,它的构造函数可以使子类的对象实例化。

 

抽象类和一般类的异同点:

相同:都是用来描述事物,都可以进行属性和行为的描述。

不同:抽象类描述事物的信息不具体,一般类描述事物的信息具体。

代码的不同:

抽象类中可以定义抽象方法,一般类不行。

抽象类不可以实例化,一般类可以。

 

2、 抽象类一定是个父类吗?

是的,必须需要子类覆盖抽象方法后,才可以实例化,使用这些方法。

abstract classDemo extends XXX

{

 

}

class Subextends Demo

 

3、 抽象类中可以不定义抽象方法吗?

可以的,仅仅是让该类不能创建对象。

 

4、 抽象关键字abstract和哪些关键字不能共存?

final:最终,与abstract抽象需要子类覆盖抽象方法冲突

private:私有不能覆盖

static:抽象方法被调用,没有意义

 

抽象类中所有的方法都是抽象的。

这时,可以把抽象类用另一种形式来表示—接口。

初期可以理解为接口是特殊的抽象类。

 

定义接口;

interface Inter

{

     public static final int NUM = 4;

      public abstract void show1();

          public abstract void show2();

}

接口中的成员和class定义不同之处:

接口中常见的成员有两种:1、全局变量;2、抽象方法。

而且都有固定的修饰符。

共性:

成员都是public修饰的

 

接口的特点:

1、 接口不可以实例化;

2、 需要覆盖了接口中的所有的抽象方法的子类,才可以实例化。否则,该子类还是一个抽象类。

3、 接口是用来被实现的。

 

类与接口之间的关系是:实现关系。

Java中不直接支持多继承,而是对该机制进行改良,通过接口来解决问题,将多继承转换成了多实现。

 

一个类继承一个类的同时,还可以实现多个接口,避免了单继承的局限性。

继承是为了获取体系的基本功能,想要扩展功能可以通过实现接口来完成。

 

类与类之间,继承关系,is a

类与接口,实现关系,like a

接口与接口,继承关系,并且多继承

 

为了方便创建Inter接口的子类对象,可以用一个类先把接口中的所有方法都空实现,该类创建对象没有意义,所以可以将该类抽象,这就是没有抽象方法的抽象类。

 

接口的思想;

笔记本电脑的USB接口;

1、 接口的出现扩展了功能,

2、 接口其实就是暴露出来的规则,

3、 接口的出现降低了耦合性、解耦。

 

接口的出现,一方在使用接口,一方在实现接口。

 

抽象类与接口的区别

类用于描述本类事物中的共性基本功能;

接口用于定义的都是事物的额外功能

抽象类与接口的区别:

1、 类与类之间是继承关系,is a;

类与接口是实现关系,like a;

2、 抽象类中可以定义抽象和非抽象方法,子类可以直接使用,或者覆盖使用。接口中定义都是抽象方法,必须实现才能用。

 

多态,多种形态

重点:对象的多态性。

多态在程序中的体现:父类的引用或者接口的引用指向了子类的对象。

多态的好处:提高了代码的扩展性。

多态的弊端:不能使用子类的特有方法

多态的前提:

1、必须有关系,继承、实现;

2、通常有覆盖。

 

向上转型好处:隐藏了子类型,提高了代码的扩展性。

        弊端:只能使用父类中的功能,不能使用子类的特有功能,功能被限定。

如果不需要面对子类型,通过提高扩展性,或者使用父类的功能即可完成操作,就使用向上转型。

 

如果想要使用子类的特有功能呢?

向下转型的好处:可以使用子类型的特有功能。

          弊端:面对具体的子类型,向下转型有风险,容易发生ClassCastException.只要转换类型和对象不匹配就会发生。想要安全,必须要进行判断,判断一个对象是否匹配某一个类型,需要使用一个关键字instanceof ,

对象instanceof类型

什么时候用向下转型: 需要子类型的特有方法时,但一定要判断

 

多态中对成员的调用:

1、 成员变量,

当子父类中出现同名成员变量时,

多态调用时,只看调用该成员变量的引用所属的类中的成员变量。

简单说:无论编译或者运行,都看等号的左边就行了。

 

2、 成员函数,

出现一模一样函数时,

多态调用,

编译时,看的是引用变量所属的类中的方法;

运行时,看的是对象所属的类中的方法。

简单说:编译看左边,运行看右边。

 

3、 静态函数,

出现一模一样函数时,

多态调用,

编译和运行只看引用变量所属的类中的方法,

简单说:编译运行看左边。

 

其实,真正调用静态方法是不需要对象的,直接类名调用,因为静态方法绑定到类上。所以上述情况,更多用于面试。

 

Object:    Java语言中的上帝,所有类的父亲,其中定义了所有对象都具备的功能。

 

不用再自定义方法,判断对象是否相同,因为Object父类中,已经定义了这样的方法,直接使用就可以了。但是判断的内容是根据Person的特点定义的,需要保留父类的功能声明,定义子类功能的特有内容。

使用覆盖。

想要使用子类对象的特有属性或者行为,必须对其进行向下转型,需要进行类型判断。

如果两个引用指向同一个对象,不用再转换并比较内容了,直接判断地址就行了。

如果判断姓名字符串是否相同,不要用==,字符串本身就是一个对象。

使用string类的equals方法判断。

判断的是对象的内容,用equals.

判断的是对象的地址,用==

 

内部类:其实就是将类定义到了另一个类的内部。

A类要直接访问B类中的成员时,可以将A类定义到B类中,作为B类的内部类存在。

访问规则:

内部类可以直接访问外部类中的成员;

外部类要想访问内部类,只能创建内部类的对象来访问

 

内部类相当于外部类中的一个成员,它可以被成员修饰符所修饰,public、private、static

如果内部类权限是非私有的,就可以在外部其他程序中的被访问到,就可以通过创建外部类对象完成。

 

静态内部类,相当于一个外部类。

在非静态的内部类中只允许定义静态的变量,不能定义其他静态成员。

为什么内部类就可以直接访问外部类中的成员?

因为内部类持有了外部类的引用,外部类.this

 

局部内部类,只能访问被final修饰的局部变量。

匿名内部类:简化书写的内部类。

前提:内部类需要继承或者实现外部的类或者接口。

格式:new父类or接口名(){子类的内容}

匿名内部类其实就是一个子类对象。

 

对象后面跟分号,那就是对象。

如果后面是跟大括号,那就是子类对象

 

 

DAY11

异常;java程序在 运行时期发生的不正常情况(问题)。

java就按照面向对象的思想对不正常情况进行描述和对象的封装。

问题分两种:

error:由系统底层发生的,告诉jvm,jvm告诉使用者。不做针对性处理,直接修改代码。

exception:jvm发生,并告诉给使用者。可以进行针对性的处理。

 

输出语句发生问题时,jvm就将这个已知的问题封装成了对象,

throw newArrayIndexOutOfBoundsException(1);将问题抛给调用者main函数,main没有针对性的处理方式。main就继续往外抛给调用者jvm,jvm就使用了默认的处理方式。将问题名称=信息=位置在控制台上显示出来,让调用者看到并结束程序。

 

处理方式;

1、 遇到问题不进行具体的处理,而是继续抛给调用者。

 

2、 针对性的处理方式:捕获

try

{

    //有可能发生异常的代码。

}

catch(异常类变量)

//这是真正的捕获,处理异常的代码;

finally

{

     //一定会被执行的代码。

}

 

 

在编写功能时,编写者知道该功能有可能发生问题,而这个问题很容易来自于调用者传递的参数,而导致功能无法进行。这时发生的问题就应该让调用者知道,并最好让调用者有预先的处理方式。所以在定义功能时,需要在功能上对有可能发生的问题进行声明。

声明问题需要使用关键字.throws 异常类,声明的目的就是让调用者可以进行处理。

throw与throws有什么区别?

1、 位置不同。

throws用在函数上,后面跟的是异常类,可以跟多个。

throw用在函数内,后面跟的是异常对象。

2、 功能不同。

throws用来声明异常,让调用者知道该功能有可能出现的问题,并由调用者可以给出预先的处理方式。

throw抛出具体问题对象,执行到throw功能就已经结束了,跳转到调用者,并将具体的问题对象也抛给调用者。

也就是说throw语句独立存在时,下面不要定义其他语句,因为执行不到。

 

异常体系的特殊情况;

Exception

|--Error

|--Exception

异常体系最大的特点就是体系中的类以及类产生的对象,都具备可抛性,可抛性的意思是可以被throws和throw所操作。

 

异常的原则:

1、 功能内部有异常throw抛出,功能上一定要throws声明。

内部抛什么,功能上就声明什么。

声明的目的就是为了让调用者处理,如果调用者不处理,编译失败。

 

2、 特殊情况:

当函数内通过throw抛出了RuntimeException及其子类的异常对象时,函数上可以不用throws声明。

不声明的目的就是不让调用者处理,让调用者的程序停止,要对代码进行修改。

Exception分两种:

1、  编译时会被检测的异常;

2、  运行时异常(编译时不检测)RuntimeException

 

异常:

其实就将问题封装成对象,并抛给调用者,

如果声明了,就需要调用者处理(继续声明or捕获)

什么时候声明,什么时候捕获?

功能内部可以解决,就捕获;不能解决,或者解决了还必须告诉调用者问题,这时就应该声明。

 

finally的作用是:无论是否有异常发生,都要对资源进行释放。

资源释放动作就定义在finally代码块中。

 

system.exit(0);//推出jvm,只有这种情况,finally也不执行。

 

异常的针对性处理方式:

try

{

 

}

catch()

{

}

finally

{}

的几种组合方式。

 

1、  没有资源需要释放,仅仅是处理异常。

try

{

 

}

catch()

{

}

 

2、  一个try多个catch,一般对应的是被调用的函数,抛出多个异常的情况,分别处理。

try

{

 

}

catch

{

}

catch

{

}

catch

{

}

注意:在多catch语法上特殊的地方,如果catch中的异常类存在子父类,父类的catch一定要放子类的下面,否则编译失败。

 

3、不一定要处理异常,但是有资源需要释放。

try

{

 

}

finally

{

 

}

 

覆盖时:

子类方法覆盖父类方法只能抛出父类方法异常或者该异常的子类,

如果父类方法抛出多个异常,子类只能抛出父类异常的子集,

原则:就是子类的异常必须要在父类的异常处理控制中。

 

注意:有一种情况,只能try不能throws。

被覆盖的方法没有抛出异常,

那么子类在覆盖时,子类方法中发生了异常,就只能try,无法throws声明。

例如:

 

 

 

 

 

 

 

 

 

 

interface Inter

{

     void show();

}

class Demoimplements Inter

{

public coidshow()

{

    try

{

throw newException();

}

catch(Exceptione)

    {

         throw new RuntimeException(“”);//将编译时检测异常转换成运行时异常。

}

}

}

 

DAY12

包(package)

对类文件进行分类管理;

给类提供多层命名(名称)空间;

写在程序文件的第一行;

类名的全称是包名.类名;

包也是一种封装形式

 

 

 

import关键字

 

 

 

 

DAY13多线程

进程:应用程序在内存中分配的空间。(正在运行中的程序)

 

线程:进程中负责程序执行的执行单元,也称为执行路径。

一个进程中至少有一个线程在负责该进程的运行,

如果一个进程中出现了多个线程,就称该程序为多线程程序。

 

多线程技术:解决多部分代码同时执行的需求,合理的使用cpu资源。

多线程的运行根据cpu的切换完成的,怎么切换cpu说了算,

所以多线程运行有一个随机性(cpu的快速切换造成的)。

 

jvm中的多线程:

至少有两个线程:一个是负责制定义代码运行

                一个负责垃圾回收。

通过实验:发现每次结果不一定相同,因为随机性造成的,

而且每一个线程都有运行的代码内容,这个称之为线程的任务。

之所以创建一个线程,就是为了去运行指定的代码任务。


线程的任务都封装在特定的区域中。

比如:  主线程运行的任务都定义在main方法中,

       垃圾回收线程在收垃圾都会运行finalize方法。

 

如何建立一个执行路径?

通过查阅API文档java , lang . Thread 类。

该类的描述中有创建线程的两种方式;

1、 继承Thread类。

1、 继承Thread类

2、  覆盖run方法

3、  创建子类对象就是创建线程对象

4、  调用Thread类中的start方法就可以执行线程,并会调用run方法。

start(0开启线程后,都会执行run 方法,说明run 方法中存储的是线程要运行的代码。

所以,自定义线程的任务代码都存储在run方法中。

 

调用start和调用run方法的区别;

调用start会开启线程,让开启的线程去执行run方法中的线程任务,

直接调用run方法,线程并未开启,去执行run方法的只有主线程。

 

 

 

2、 创建线程的第二种方式,实现Runnable接口。

1、 定义一个类实现Runnable。

2、 覆盖Runnable接口中的run方法,将线程要运行的任务代码存储到该方法中。

3、 通过Thread类创建线程对象,并将实现了Runnable接口的对象作为Thread类的构造函数的参数进行传递。

4、 调用Thread累的start方法,开启线程。

 

 

实现Runnable接口的好处:、

1、 避免了继承Thread类的单继承的局限性,

2、 Runnable接口出现更符合面向对象,将线程单独进行对象的封装,

3、 Runnable接口出现,降低了线程对象和线程任务的耦合性,

所以,以后创建线程都使用第二种方式。

 

多线程的安全问题:

 

产生的原因:

1、 线程任务中有处理到共享的数据,

2、 线程任务中有多条对共享数据的操作,

一个线程在操作共享数据的共存中,其他线程参与了运算,造成了数据的错误。

 

解决思想:

只要保证多条操作共享数据的代码在某一时间段,被一条线程所执行,

在执行期间不允许其他线程参与运算。

 

 

 

 

 

咋保证呢?

用到了同步代码块

synchronized(对象)

需要被同步的代码

 

同步在目前情况下保证了一次只能有一个线程在执行,其他线程进不来。

这就是同步的锁机制。

好处:解决了多线程的安全问题。

弊端:降低效率。

 

有可能出现这样一种情况:

多线程安全问题出现后,加入了同步机制,安全问题依然没有解决,咋办?

这时肯定是同步出了问题。

 

只要遵守了同步的前提,就可以解决。

同步的前提:

多个线程在同步中必须使用同一个锁,这才是对多个线程同步。

 

 

DAY14

同步函数,其实就是在函数上加上了同步关键字进行了修饰。

同步表现形式有两种:1、同步代码块,2、同步函数。

 

同步函数;

 

同步函数使用的锁是什么?函数需要被对象调用,哪个对象不确定,但是都用this来表示。

同步函数使用的锁就是this。

 

如果同步函数被static修饰呢?

static方法随着类加载,这时不一定有该类的对象,但是一定有一个该类的字节码文件对象。 这个对象简单的表示方式就是类名.class  Class

 

懒汉式,延迟加载模式。

在多线程并发访问时,会出现线程安全问题。

加了同步就可以解决问题,无论是同步函数,还是同步代码块,都行。

但是效率低了。

怎么解决效率低的问题?

可以通过if对单例对象的双重判断的形式。

例:

 

 

饿汉式,相对与多线程并发,安全!

 

 

同步函数与同步代码块的区别:

同步代码块使用任意的对象作为锁,

     同步函数只能使用this作为锁。

如何区别使用:

如果说,一个类中只需要一个锁,这时可以考虑同步函数,使用this,写法简单;

但是,如果一个类中需要多个锁,还有多个类中使用同一个锁,这时只能使用同步代码块。

开发中建议使用同步代码块。

 

死锁

一一同步嵌套,

——冻结,wait()

 

生产者、消费者

通过同步,解决了没生产就消费的问题。

但是,出现了连续生产却没有消费的问题,与生产一个,消费一个的需求情况不符。

使用等待唤醒机制。

wait():该方法可以让线程处于冻结状态,并将线程临时存储到线程池中。

notify():唤醒指定线程池中的任意一个线程。

notifyAll():唤醒指定线程池中的所有线程。

 

这些方法必须使用在同步中,因为它们是用来操作同步锁上的线程的线程的状态的。

在使用这些方法时,必须标识它们所属与的锁,

标识方式就是:  锁对象.wait();   锁对象.notify();   锁对象.notifyAll();

相同锁的notify(),可以获取相同的wait();

 

 

多生产多消费。

问题1:

     重复生产,重复消费。

原因:经过(等、资格)分析,发现被唤醒的线程没有判断标记就开始工作(生产or消费)。导致了重复的生产和消费的发生。

 

解决:被唤醒的线程必须判断标记。

     使用while循环。

       问题2:

              死锁了,所有的线程都处于冻结状态。

              原因:本方线程在唤醒时,又一次唤醒了本方线程,而本方线程循环判断标记,又继续等待。

              解决:希望本方唤醒对方线程,问题解决。

              可以使用notifyAll()方法。

              全唤醒后,既有本方,也有对方。本方醒后,会判断标记继续等待。

              对方判断标记,线程执行。

 

已经实现了多生产多消费,

但是存在效率低下的问题,因为notifyAll也唤醒了本方,做了不必要的判断,

同时唤醒对方全部,但是某一时刻只能有一人消费。

理想情况:只唤醒对方一个。

 

DAY15

解决多生产多消费的效率问题。

使用了JDK1.5 java. util. concurrent. locks 包中的对象。

Lock接口:它的出现比synchronized有更多的操作,

           lock():获取锁。

                     unlock():释放锁。

 

同步代码块或者同步函数的锁操作是隐式的。

JDK1.5 Lock接口,按照面向对象的思想,将锁单独封装成了一个对象,并提供了对锁的显示操作。

 

Lock接口就是同步的替代。

将线程中的同步更换为Lock接口的形式,

 

替换完运行失败,因为wait没有了同步区域,没有了所属的同步锁。

同步升级了,其中锁已经不是任意对象,而是Lock类型的对象。

那么和任意对象绑定的监视器方法,是不是也升级了,有了专门和Lock类型锁的绑定的监视器方法呢?

查阅API,condition接口替代了object中的监视器方法。

 

以前监视器方法封装到每一个对象中,

现在将监视器方法封装到了condition对象中。

方法名为:await  signal signalAll

 

监视器对象condition如何和Lock绑定?

可以通过Lock接口的newCondtion()方法完成。

 

但是,问题依旧,一样唤醒了本方,效率仍旧低。

--

---

-----

 

wait()和sleep()的区别:

1、 相同:

可以让线程处于冻结状态。

2、 不同:

a)        wait() 可以指定时间,也可以不指定。

sleep() 必须指定时间。

b)       wait() 释放cpu资源,释放锁。

sleep() 释放cpu资源,不释放锁。

 

异常会提示发生在哪个线程上,

异常会结束线程任务,也就是可以结束所在线程。

 

进程的异常提示:发生在哪个线程上 + 异常名 + 异常信息 + 异常位置

 

 

             

 

 

DAY16

eclipse常用快捷键:

       alt+/                   功能辅助键

       shift+enter                         光标跳到下一行应该在的行首

    ctrl+shift+o                        导包

       ctrl+1                                   错误解决方案   

       ctrl+d                               删除单行,选择多行再ctrl+d,可删除多行

       ctrl+alt+上下键                向上复制或向下复制

       alt+上下键                      向上或向下移动

       ctrl+/                                 单行注释,再次ctrl+/ 可取消注释

ctrl+shift+/                         多行注释,先选择注释范围,再调用快捷键;若要取消,则光标放在注释范围内,ctrl+shift+\ 可取消注释

       ctrl+shift+x                       调整为大写

       ctrl+shift+y                         调整为小写

      

 

 

错误提示:大叉-----语法格式错误,ctrl+1无法解决

          小叉-----可以通过ctrl+1解决

 

 

基本类型数值可以通过比较运算符大小和相等,> < ==

对象也可以比较是否相等,谁大谁小,都是通过方式完成。

对象比较相同:Object类中booleanequals(Object obj):子类一般情况下都会复写,建立自己判断的依据。

对象比较大小用的也是方法,该功能有三种情况,所以使用int类型,正数、负数、零。

前者大于后者返回正数,前者小于后者返回负数,前者等于后者返回零。

 

 

面试可能出现的题目:

确定哪个是长的哪个是短的。

获取子串

结果

 

练习:

步骤思想:

 

 

DAY17

StringBuffer:字符串缓冲区,作为一个字符容器

特点:

1、 长度可以变化

2、 可以对内容通过指定方法进行修改

3、 容器对象一般都会具备对容器的元素进行操作的功能,增删改查

4、 缓冲区可以存储不同类型的数据

5、 最终缓冲区存储完的数据都会变成字符串

 

存储数据过程:

在内存中的过程:

1、 创建一个字符串缓冲区容器

2、 将要组成字符串的元素先存储起来

3、 最后将缓冲区填充数据变成字符串

 

 

缓冲区可以对数据进行临时存储

缓冲区的常见方法:

添加元素:

StringBufferappend(各种类型的数据);追加

StringBufferinsert(index,各种类型的数据);指定位置添加

 

 

什么时候用字符串缓冲区:

   数据很多,个数无所谓确定,;类型无所谓确定,只要最后都转成字符串。

 

使用的局限性:

1、 必须最终转成字符串

2、 无法对存储进来的元素进行单独操作,因为存储进来的元素都变成字符串。

 

 

 

 

 

 

 

DAY17

基本类型对象包装类:

JDK1.5以后的技术,自动装箱自动拆箱,像操作int一样的操作Integer

 

 

 

 

 

API集合框架,

      

Collection接口中的共性功能

1、 添加

booleanadd(Object obj); 一次添加一个

booleanaddAll(Collection c);将指定容器中的所有元素添加。

 

2、 删除

void clear();

boolean remove(object o);

booleanremoveAll(Collection c);

booleanretainAll(Collection c);

 

3、获取长度

       intsize();

4、判断

       booleanisEmpty();

       booleancontains(Object o);

       booleancontainsAll(Collection c);

5、将集合转换成数组

       toArray();

       toArray{[]};

6、取出集合元素

       Iteratoriterator()

       获取集合中元素上迭代功能的迭代器对象。

       迭代:取出元素的一种方式。有没有啊?有!取一个;还有没有啊?有!取一个;还有没有啊?没有,算了。

       迭代器:具备迭代功能的对象。

       迭代器对象不需要new,直接通过interator()方法获取即可。

 

       迭代器是取出Collection集合中元素的公共方法。

 

 

 

 

带ALL的方法:

 

collection:

       |---List:有序(存入的顺序和取出的顺序一致),有索引,允许重复元素。

       |---Set:不允许重复元素。

 

重点:List接口中的特有方法

       它的特有方法都是围绕索引定义的。

支持增删改查:

增:

add(index, element)

删:

remove(index);

改:

set(index, newement);

查:

int indexof(element);  ----根据元素拿到索引

element get(index); ----根据索引拿到元素

 

 

在遍历的过程中,如果遍历到abc2,添加一个元素haha

 

List集合的具体子类,子类之所以区分是因为内部的数据结构(存储数据的方式)不同。

   |--Vector:数据结构是数组。数组是可变长度的(不断new新数组并将原数组元素复制到新数组)。线程同步,增删和查询都慢!

|--ArrayList:数组结构,长度可变,线程不同步,替代了Vector。增删速度不快,查询速度很快。

|--LinkedList:链表结构,线程不同步。增删速度很快,查询速度较慢。

Set集合:不允许重复元素,和Collection的方法相同。Set集合取出方法只有一个:迭代器。

|--HashSet:哈希(散列)表结构。

       如何保证唯一性?

       不允许存储重复元素,因为会发生查找的不确定性。

       不保证存入和取出的顺序一致。

       比数组的查询效率高

用于存储元素和哈希值对应关系的容器称之为哈希表。

 

       元素必须覆盖hashcode和equals方法。

覆盖hashcode方法是为了根据元素自身的特点确定哈希值。

覆盖equals方法,是为了解决哈希值的冲突。

 

       |--TreeSet:二叉树数据结构,可以对元素进行排序。不同步。

              如何保证元素唯一性?

              参考的就是比较方法的返回值是否是0,是,就是重复元素,不存。

              排序方式:需要元素具备比较功能,所以元素需要实现Comparable接口。

                              覆盖CompareTo方法。

需求中也有这样一种情况:元素具备的比较功能不是所需要的,也就是不想按照自然排序的方法,而是按照自定义的排序方式,对元素进行排序。而且,存储到TreeSet中的元素万一没有比较功能,该如何排序呢?

这时就只能使用第二种比较方式----让集合具备比较功能。定义一个比较器。

 

              实现Comparator接口,覆盖compare方法。将Comparator接口的对象,作为参数传递给TreeSet集合的构造函数。

              比较器更为灵活,自然排序通常作为元素的默认排序。

 

技巧:JDK1.2以后出现的集合框架中的常用子类对象,存在的规律。

     前缀名是数据结构名,后缀名是所属体系名。

ArrayList:数组结构,看到数组,就该知道查询快,看到list,就知道可以重复,可以增删改查。

LinkedList:链表结构,增删快。xxxFirst  xxxLast.  xxx:add get remove

 

HashSet:哈希表,就要想到元素必须覆盖hashCode equals,不保证有序,看到Set,就知道不可以重复。

 

LinkedHashSet:链表+哈希表,可以实现有序,因为有链表。

 

TreeSet:二叉树,可以排序,就要想到两种比较方式,一种是自然排序Comparable,一种是比较器Comparator.

 

 

JDK1.5特性:

增强for循环。作用:用于遍历collection集合or数组。

格式:

for(元素类型变量:collection容器or数组)

传统for循环和增强for循环有什么区别?

增强for必须有被遍历的目标,该目标只能是collection  or 数组。

 

对于数组的遍历,如果不操作其角标,可以使用增强for,如果要操作角标,使用传统for。

 

 

Enumeration:枚举。

具备枚举取出方式的容器只有Vector.

‘’

 

 

 

 

 

 

 

 

 

 

 

 

泛型:

在JDK1.4版本之前,容器什么类型的对象都可以存储。但是在取出时,需要用到对象的特有内容时,需要做向下转型。 但是对象的类型不一致,导致了向下转型发生了ClassCastException异常。 为了避免这个问题,只能主观上控制往集合中存储的对象类型保持一致。

JDK1.5以后解决了该问题,在定义集合时,就直接明确集合中存储元素的具体类型。这样,编译器在编译时,就可以对集合中存储的对象类型进行检查。一旦发现类型不匹配,就编译失败。这个技术就是泛型技术。

 

好处:1、将运行时期的问题转移到了编译时期,可以更好的让程序员发现问题并解决问题。

        2、避免了向下转型的麻烦。

总结:泛型就是应用在编译时期的一项安全机制。

 

泛型的擦除:编译器通过泛型对元素类型进行检查,只要检查通过,就会生成class文件,但在class文件中,就将泛型标识去掉了。

 

泛型的表现:

泛型技术在集合框架中应用的范围很大。

什么时候需要写泛型呢?

1、只要看到类,或者接口在描述的时候右边定义<>,就需要泛型。其实是容器在不明确操作元素的类型的情况下,对外提供了一个参数<>。使用容器时,只要将具体的类型实参传递给该参数即可。

说白了。泛型就是---传递类型参数。

 

在不明确具体类型的情况下,可以使用通配符来表示。

 

泛型的限定:

       ?  extends E :接收E类型或者E的子类型。

       ?  super E :接收E类型或者E的父类型。

 

什么时候会用到上限?

       一般往集合存储元素时,如果集合定义了E类型,通常情况下应该存储E类型的对象。、

对E的子类型对象E类型也可以接受,所以这时可以将泛型从E改为 ? extends E .

 

什么时候用到下限?

       当从容器中取出元素操作时,可以用E类型接收,也可以用E的父类型接收。

 

 

Map:双列集合,一次存一对,键值对,要保证键的唯一性。

共性功能:

1、添加。

       v.put(key,value);            存储键值对,如果键相同,会出现值覆盖。

       putAll(Mapmap);

2、删除。

       voidclear();

       vremove(key);

3、判断。、

       booleancontainsKey(object)

       booleancontainsValue(object);

       booleanisEmpty();

4、获取。

       vget(key);

       intsize();

 

 

keySet,取出所有的键,并存储到set集合中,map集合没有迭代器,但是可以将map集合转成set集合,再使用迭代器就行了。

 

entry就是map接口中的内部接口。

 

Map

       |--Hashtable:哈希表,是同步的,不允许null键,null值。

       |--HashMap:哈希表,是不同步的,允许null键,null值。

       |--TreeMap:二叉树,不同步的,可以对map集合中的键进行排序。

 

 

什么时候使用map集合?

       当需求中出现映射(对应)关系时,应该最先想到用map集合。

 

 

集合框架的工具类。

Collections:定义的都是操作Collection的静态方法。

       1、对list排序。

       2、逆序。

       3、max min

       4、二分查找。

       5、将非同步集合转成同步集合。

 

Arrays:用来操作数组的工具类,方法都是静态的。

       将数组转成list集合,就是为了使用集合的方法操作数组中的元素

       如果数组中都是引用数据类型,转成集合时,数组元素直接作为集合元素。

       如果数组中都是基本数据类型,会将数组对象作为集合中的元素。

      

 

 

集合转成数组,CollectiontoArray

       传入的数组长度,如果小于集合长度,方法中会创建一个新的长度和集合长度一致的数组。

       如果传入的数组长度大于等于集合长度,会使用传入的数组。所以建议长度定义为集合的size();

 

为什么要把集合转成数组?

       就是为了限定对元素的操作,比如增删。

 

可变参数需要注意:只能定义在参数列表的最后。

 

 

System:全是静态的属性和行为。

属性:

       out:标准输出流,默认对应设备显示器。

       in:标准输入流,默认的设备键盘。

 

 

日期对象和毫秒值的转换:

日历对象Calender-时间设置&偏移

 

递归:函数自身调用自身,函数内部又使用到了该函数功能。

什么时候使用?

功能被重复使用,但是每次该功能使用参与运算的数据不相同,可以考虑递归方式解决。

使用时,一定要定义条件。

 

 

创建字节输出对象,用于操作文件,在对象初始化时,必须明确数据存储的目的地。

 

输出流所关联的目的地,如果不存在,会自动创建,如果存在,则覆盖。

 

 

 

读取键盘录入专业。Scanner=流+正则表达式。方法都是按照某种规则在读取数据。

 

File:IO技术用于操作设备上的数据,而数据最常见的体现方式是文件File。

先了解文件的操作。

创建、删除、存在、隐藏、获取、、、、、

 

需求:怎么操作文件的数据?

       使用IO流对象,而且文件数据都是字节存在,学习了可以操作文件的字节流。

       InputStream

              |--FileInputStream

       OutputStream

              |--FileOutputStream

为了提高操作效率,引入缓冲区。

       InputStream

              |--FileInputStream

              |--FilterInputStream

                     |--BufferedInputStream

       OutputStream

              |--FileOutputStream

              |--FilterOutputStream

                     |--BufferedOutputStream

发现,文件数据,媒体文件字节流没问题。

但是对于文本文件,想要操作文件中的中文数据时,字节流只能操作字节,需要我们字节解码成字符,麻烦。

所以到API找对象,发现字符流中有字节和字符的桥梁,也就是转换流。

              Reader

                     |--InputStreamReader:字节---》字符。

              Writer

                     |--OutputStreamWriter:字符---》字节。

它们的出现解决了中文的编码转换问题。

为了便捷操作字符文件,找到了转换流的子类,但是它有局限性,只能操作文件,而且是默认编码。如果不操作文件,而且编码不是默认的,需要使用转换流。

       Reader

                     |--InputStreamReader:字节---》字符。

                            |--FileReader

       Writer

                     |--OutputStreamWriter:字符---》字节。

                            |--FileWriter

为了提高字符流的操作效率,引入字符流的缓冲区。

       Reader

                     |--InputStreamReader:字节---》字符。

                            |--FileReader

                     |--BufferedReader:readLine()

       Writer

                     |--OutputStreamWriter:字符---》字节。

                            |--FileWriter

                     |--BufferedWriter:newLine();

 

缓冲区原理:

       临时存储数据的方法,减少对设备操作的频率,提高了效率,其实就是将数据临时缓存到了内存(数组)中。

 

模拟一个BufferedReader

 

Writer

       |--TextWriter

       |--MediaWriter

在对数据写入操作过程中,希望提升效率。

要对操作文本的对象提升效率,使用缓冲区技术。

 

Writer

       |--TextWriter

              |--BufferedTextWriter

       |--MediaWriter

              |--BufferedMediaWriter

       |--AudioWriter

              |--BufferedAudioWriter

 

这样的体系,为了增加一些功能,而通过产生子类来完成,会导致继承体系变得很臃肿。

重新思考体系的设计问题,都是在写的方法进行效率的提升,为什么不将该功能进行单独的封装?要提升哪个具体对象,将哪个具体对象交给该功能不就可以了吗?

 

 

Writer

|--TextWriter

|--MediaWriter

|--AudioWriter

|--BufferedWriter

 

TextWriter tw = new TextWriter();

BufferedWriter bufw = newBufferedWriter(tw);

 

解决:可以给对象提供额外的功能(职责)。比继承这种方式更为灵活。

装饰设计模式(Wrapper,Decorator)

 

Properties

       特点:1、Hashtable的子类,map集合中的方法都可以用,

                2、该集合没有泛型,键值都是字符串,

                3、它是一个可以持久化的属性集,键值可以存储到集合中,也可以存储到持久化的设备上。

             键值的来源也可以是持久化的设备。

 

 

IO流的规律总结:解决的问题,就是开发中具体要使用哪个流对象的问题。

 

1、明确数据源,数据汇(数据目的)

其实就是在明确要使用的IO体系。InputStreamOutputStream  Reader Writer

需求中操作的是源,意味着是读。

InputStream   Reader

 

需求中操作的是目的:意味着是写。

OutputStream   Writer

 

2、操作的数据是否是纯文本数据?

       是,字符流。

       否,字节流。

 

       是,并且是源。Reader

       是,并且也是目的,Writer.

 

通过前两个明确,明确了具体要使用的体系。

接下来应该明确具体的体系中要使用哪个对象。

3、明确要操作的具体设备,每个设备都有对应的流对象。

       源设备:

硬盘,能操作File的流对象都是,File开头;

              键盘,System.in;

              内存,数组;

              网络,socket流。

 

       目的设备:

              硬盘,能操作File的流对象都是,File开头;

              显示器,System.out

              内存,数组;

              网络,socket流。

 

到第三步明确就可以找到具体的流对象了。

 

4、需要额外功能吗?

       需要高效吗? 缓冲区,Buffered开头。

       需要编码转换吗? 转换流。

 

 

IO包中的其他功能流对象。

功能流对象

特点:解决的问题,特有方法。

 

打印流----输出流

PrintStream(字节流) PrintWriter(字符流)

特点:打印,不抛异常。

打印目的:File对象,字符串路径,字节输出流。

 

解决问题:方便地打印各种数据值表现形式。

              它的打印方法可以保证数值的表现形式不变,写的是什么样子,目的就是什么样子。

 

PrintWriter:一样具备打印功能。

       目的:File对象,字符串路径,字节输出流,字符输出流。

 

序列流

特点:流对象的有序排列。

解决问题:将多个输入流合并成一个输入流,将多个源合并成一个源,对多个源的操作会变的简单。

功能:特殊之处在构造函数上,一初始化就合并了多个流进来。

 

使用场景之一:对多个文件进行数据的合并,多个源对应一个目的。

 

Person类的对象如果需要序列化,就需要实现Serializable标记接口。

该接口给需要序列化的类,提供了一个序列版本号,serialVersionUID.

该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

 

用于操作对象的流对象,对象的序列化。

ObjectInputStream  ObjectOutStream

特点:用于操作对象。

解决问题:可以将对象进行序列化和反序列化。注意:对象序列化一定要实现Serializable接口。为了给类定义一个SerialVersionUID。

功能:ObjectInputStreamreadObject()    ObjectOutputStreamwriteObject()

关键字:瞬态,transient

 

----

RandonAccessFile:

特点:只能操作文件。

       既能读,又能写。

       维护了一个byte数组,内部定义了字节流的读取和写入

       通过对指针的操作可以实现对文件的任意位置的读取和写入。

功能:getFilePointerseek用于操作文件指针的方法。

 

-----------

管道流

特点:读取管道和写入管道可以连接。

需要使用多线程技术,单线程容易死锁。

 

功能:connect()

 

 

正则表达式:

专门用于对字符串的操作

规则由符号组成的,使操作字符串变得简单。

弊端:阅读性降低了

所以学习正则其实就是学习符号的使用。

1、匹配

String类中提供了匹配boolean matches(regex)的方法。

 

 

2、切割

 

 

3、替换

4、获取

 

 

 

 

网络编程

七层简述:

 

常见的客户端和服务端有哪些?

客户端:浏览器

服务端:Tomcat

如果请求多图片的网页,请求的次数很多,有多少资源(html文件、图片文件、css文件、js文件等),就需要请求多少次。

 

网络架构:

 

两种

C/S Client Server

特点:

1、客户端和服务端都需要编写,

2、客户端需要维护,

3、客户端可以分担部分运算。

如果大型运算,比如网络游戏。

 

B/S Browser Server

特点:

       1、只需要编写服务端,客户端其实就是已有的浏览器,

       2、客户端不需要维护,

       3、运算全在服务器端。

例:网页游戏。

 

 

反射技术:、

       动态的获取类以及类中的成员,并可以调用该类成员。

以前是有什么类,就new什么对象,没有类,给什么类就new什么对象。

 

无论new什么对象,都需要先获取字节码文件。如何获取?

java以对字节码文件进行了描述用的Class类完成的。

如何获取一个字节码文件的对象?

方式一:ObjectgetClass();方法。

发现在反射技术里,该方法不合适,反射技术不明确具体类。

 

方式二:所有的数据类型都有自己对应的Class对象,表示方式很简单。

每一个数据类型都有一个默认的静态的属性 .class 用该属性就可以获取到字节码文件对象。

缺点:虽然不用对象调用了,还是要用到具体的类调用静态属性。

 

 

HTML

标签分两种:---标签名不能以数字开头

1、有开始,有结束,用于封装数据。

2、有开始,直接在内部结束,功能的标签。

换行标签:

分隔线:


 

标签操作思想:

HTML语言的强大之处在于:提供标签将数据封装,给数据提供标记,这样就可以方便的对数据进行操作(html操作,css操作,javascript操作)。

       html操作:指的就是用标签中的属性来完成对数据操作。

 

 

 

表单

注意:表单组件都需要定义name和value属性,目的是为了让服务器端获取客户端提交的数据,对于文本框、密码框、文本区域可以不指定value属性,因为输入的内容就是value的值。

 

 

GET和POST的区别

1、存储方式

GET提交,会将提交的信息显示在地址栏。

POST提交,不会将提交的信息显示在地址栏。

2、敏感信息

GET提交,对于敏感信息不安全。

POST提交,对于敏感信息安全。

3、提交数据体积

GET提交,因为存储到地址栏,数据体积有限。

POST提交,可以提交大体积数据。

4、封装方式

GET提交,将提交的数据封装在请求头的请求行中。

POST提交,将提交的数据封装在请求体中。

 

GET提交中文,Tomcat服务器,需要先通过ISO8859-1先编码,再解码。

POST提交中文,可以先通过ISO8859-1先编码,再解码的方法,也可以直接通过服务器端的request对象的setCharacterEncoding(“gbk”);进行直接解码。

 

综上:表单提交建议使用POST提交。

 

和服务端交互的三种方式:

1、地址栏输入url地址,GET

2、点击超链接,GET

3、表单,GET   POST

 

如果在表单页面上加入了校验,判断每一个组件,只要有一个组件填写错误,无法提交。

问题一:服务端在收到该数据时,还需要再次校验吗?

需要,为了安全性

问题二:如果将校验定义在服务器端,表单页面还需要校验吗?

需要,为了增强用户的体验效果,同时减轻服务器端的压力。

 

CSS

标签分类:

1、块级标签(块级元素),结尾处后换行。 div  dl  table tr  td

2、行内标签(行内元素),结尾处没有换行。 span  a  img input

 

css和html相结合的方式:

方式一、使用了html标签中的一个属性style

方式二、使用style标签提到代码复用性

 

选择器:

1、html标签名选择器,指定要加载样式的标签。

2、类class属性选择器,使用的是标签中的class属性,专门给css提供操作的属性。

用点标识。

3、id选择器,使用的是标签中的id属性,用的是#标识的。

id一般情况下在html标签中需要保证唯一性,不仅可以给css使用,还可以javascript使用。

       何时使用id?

       对html中封装待定区域的标签,为了样式加载或者获取该标签方便,使用id。

 

三种基本选择器 的优先级:

标签选择器

 

扩展选择器:

       关联选择器

       组合选择器

 

伪元素选择器,元素的某种状态,

       比如超链接:四种状态,未访问(选择器:link) 悬停状态(:hover) 点击状态(:active) 访问后(:visited)

执行顺序:

 

 

Javascript

DOM:document object model 文档对象模型

 

文档:标记型文档(html  xml)

对象:将文档或者文档中的标签等内容都封装到了对象中

模型:只要是标记型文档都通用。

 

为了实现动态效果,需要对页面中的标签进行操作,操作所需的属性和行为都可以定义到该标签对象中。只要找到了要操作的标签,就可以调用该标签对象中的属性和方法,来完成对该标签的操作。所以就需要有一个可以将标签解析成对象的技术,而这个技术就是DOM。

 

到底如何解析的呢?

从标记型文档开始,逐一解析,将标记型文档封装成document,接着将解析到的标签按照层次关系封装成对象,以及属性和文本全都变成对象。

 

最后在内存中形成了一个具有层次关系的DOM树,通过书中的节点对象的方法就可以对这些节点进行操作。

可以实现最基本的节点的操作:增删改查。

 

-----------------

DHTML:动态的html,包含html, css,Javascript, dom

 

HTML:负责提供标签,对数据进行标记封装。

CSS:负责提供样式属性,对数据进行样式的定义。

DOM:负责将标记文档和标签等内容解析成对象,并在对象中定义属性和行为,就可以指挥对象做事情。

Javascript:负责的是页面的行为(该怎么动),动态效果的体现,需要程序语言来完成。

 

BOM:Brower Object Model, 浏览器对象模型。

将浏览器也封装成了对象。

window

       |---history:可以操作历史记录的对象。

       |---location:可以操作地址栏的对象。

       |---document:可以操作文档数据的对象。

 

 

DOM的编程思想:其实就是不断的对dom树中的节点进行操作,而操作节点的前提就是必须先获取节点,如何获取节点才是最重要的。

一个页面中如何获取到其他节点,document对象最清楚。

 

getElementById  获取对ID标签属性为指定值的第一个对象的引用。

getElementByName根据NAME标签属性的值获取对象的集合。

getElementByTaName  获取基于指定元素名称的对象集合。

你可能感兴趣的:(java基础学习笔记)