一、数组
public class Main {
public static void main(String [] args){
//在栈中创建应用数组和对象变量
int [] x;
//在堆中开辟一块内存存放数组的位置
x=new int[100];
//将引用变量设置为null 堆中数据将无法得到引用,会启动Java中的垃圾回收机制从堆中清除出去,再次引用会出现空指针异常
x=null;
//静态数组不能直接定义数组的长度
int []y=new int[]{7,5,6};
//使用System.arraycopy()函数拷贝数组
//用Arrays.sort来排序数组
Arrays.sort(y);
//获取数组的长度
for(int i=0;i<y.length;i++){
System.out.println("y["+i+"]="+y[i]);
}
//局部变量不会自动初始化
//在栈中的局部变量y没有指向堆中的对象
int [] z=new int[10];
//将x中的元素,从下标0开始,拷贝到y中,从下标0拷贝,一共3个
System.arraycopy(y, 0, z, 0, 3);
for(int i=0;i<z.length;i++){
System.out.println("z["+i+"]="+z[i]);
}
//Java中的顺序结构
//多维数组
//每个多维数组有2个一维数组,每个一维数组有3个元素
int [][]xx=new int [2][3];
xx[0][0]=3;
xx[1][2]=6;
for(int i=0;i<xx.length;i++){
for(int j=0;j<xx[i].length;j++){
System.out.println("xx["+i+"]["+j+"]="+xx[i][j]);
}
}
}
}
二、面向对象
1.特点:适应性强,可拓展性好;从任务的执行者变成了指挥者
2.特征:
封装:封装是将不需要对外提供的属性和细节隐藏,仅对外提供公共的访问方式提高了代码的安全性,复用性和可维护性
继承:•一个类只能有一个父类,单继承,多实现,可以分层继承
•子类具有父类的非私有属性和方法
•被final修饰的类不能被继承
•让类与类之间产生关系,继承是多态的前提
多态:一种事物的多种形态,多态存在的三个必要条件
①有继承关系(接口与实现类也能形成多态关系)
②子类强制重写父类抽象方法
③父类引用方法时,指向子类对象的方法
3.类与对象:
类:是一堆有共同特征的事物的描述,是概念,定义。
对象:是某类事物的具体体现,也称实例。
❤类是对象的抽象,对象是类的具体体现。
4.成员方法:在类里面的方法叫全局方法
成员属性:在类里面的属性叫全局属性
局部变量:类内的方法中定义的变量(必须手动赋值)
成员变量:类中成员位置定义的变量(系统自动初始化)
int类型默认是0;double类型默认是0.0;String类型默认是null
成员位置和局部变量的区别:定义位置不同,生命周期不同,初始化值不同,内存中的存储位置不同
5.this在本类中调用自己的属性和方法
super在子类中调用父类的属性和方法
6.this作为对象的默认引用有两种情况:
①构造器中引用该构造器正在初始化的对象
②在方法中引用调用该方法的对象
7.局部变量隐藏成员变量时,要是用this关键字
public class Preson {
//属性类型 属性名 类的成员变量
private int age;
private String name;
//方法返回值类型 方法名(参数列表) 类的成员函数
void shout(){
//方法的局部变量
// int age=18;
//访问到的是方法中的局部变量
System.out.println("My age is "+age);
}
//加void这个方法不执行
// public Preson(){
// System.out.println("the constructorl is calling!");
// }
// public Preson (String name){
// name=name;
// }
// public Preson(String name,int age){
// name=name;
// age=age;//第一个age是成员变量,第二个age是
// }
public void setAge(int age) {
if (age<0) {
return;
}
age = age;
}
public int getAge() {
return age;
}
public void getSomeOne(Preson p){
p.shout();
}
public static void main(String [] args){
//当一个对象被创建时,会对其中各种类型的成员变量自动进行初始化赋值
Preson p1=new Preson();
Preson p2=new Preson();
p1.age=-2;
p1.shout();
p2.shout();
p1.getSomeOne(p2);
String s1=new String("abc");
String s2=new String("abc");
String s3=s1;
//s1==s2----->equels比较地址值相等,俩个对象中的内容是否相等
//s1==s3----->==比较值相等
if (s1==s3) {
System.out.println("true");
}else {
System.out.println("false");
}
}
}
class Container{
Component comp;
public void addComponent(Component comp){
// this.comp=comp;
//在构造方法里传入一个容器(这个容器属于这个组件)
// comp=new Component(new Container());
//this在本类中调用自己的属性和方法
comp=new Component(this);
}
}
class Component{
Container con;
public Component(Container con){
this.con=con;
}
}
三、垃圾回收过程分析
•C++中的析构方法
•finalize():是Object中的方法,当垃圾回收器将回收对象从内存中清除出去之前会调用finalize(),但此时并不代表该回收对象一定会“死亡”,还有机会“逃脱
•System.gc的作用:将创建完的对象垃圾回收
public Preson(){
System.out.println("the constructorl is calling!");
}
public void finalize(){
System.out.println("Object is going!");
}
public static void main(String [] args){
new Preson();
new Preson();
//垃圾回收器
System.gc();
}
四、static关键字
1.作用:静态修饰符 可以修饰成员变量和成员方法
2.static关键字特点:
⑴随着类的加载而加载
⑵优先于对象存在
⑶被类的所有对象共享
⑷这也是我们判断是否使用静态关键字的条件
⑸可以通过类名调用
3.static关键字注意事项
⑴在静态方法中是没有this和super关键字的
⑵静态方法只能访问静态的成员变量和静态的成员方法,而不能直接访问类中的非静态成员,对于非静态的方法和变量,需要先创建类的实例对象才能使用,而静态方法不需要创建任何对象
public class PassParam {
int x;
public static void main(String [] args){
// int x=5;
// change(x);
// System.out.println(x);
PassParam obj=new PassParam();
obj.x=5;
change(obj);
System.out.println(obj.x);
int []x=new int[1];
x[0]=5;
//栈中对象的变量等于堆中对象的首地址
change(x);
System.out.println(x[0]);
}
// public static void change(int x){
// x=3;
// }
public static void change(PassParam obj){
obj.x=3;
}
public static void change(int[] x){
x[0]=3;
}
}
class Chinese{
//不加static每次调用这个方法都会产生一个对象,直到消耗完才结束
//加static在调用这个方法前就创建完成对象
static Chinese objRet=new Chinese();
//被static修饰的成员变量
private static int count=0;
static String country="中国";
static {
count=4;
System.out.println("static code");
}
String name;
int age;
//静态方法不能访问非静态的成员方法objRet
public static Chinese getInstance(){
return objRet;
}
public Chinese(){
System.out.println(++count);
}
//静态的方法
static void sing(){
System.out.println("啊");
}
//非静态的成员方法使用时要创建一个对象,就可以访问静态的成员变量和非静态的成员变量
void singOutCountry(){
//类 对象 方法
System.out.println(country);
sing();
}
}
class TextChinese{
public static void main(String []args){
System.out.println(Chinese.country);
Chinese chinese=new Chinese();
chinese.singOutCountry();
System.out.println(chinese.country);
//类名.方法 JVM虚拟机在用到这个类的时候加载
Chinese.sing();
//Chinese这个类的实例对象,通过实例对象来调用静态的方法
System.out.println("begin");
new Chinese().sing();
System.out.println("end");
new Chinese().singOutCountry();
Chinese obj1=chinese.getInstance();
Chinese obj2=chinese.getInstance();
//如果相等为true,不相等为flase
System.out.println(obj1==obj2);
}
}
五、内部类
1.定义:一个类中还包含着另外一个类
2.分类:
•成员内部类:内部类写在了类中成员成员方法的外部,跟成员变量成员方法是同一级别
•局部内部类:在方法中定义的内部类(不加修饰符,只能在当前方法中使用)在局部内部类中访问局部变量加final关键字
•静态内部类:使用static修饰的成员内部类
•匿名内部类:没有名字的内部类
3.匿名内部类的格式:new的后面,用其隐含实现一个抽象类的子类或接口的实现一个类
六、类的继承
1.通过继承可以简化类的定义
2.Java支持单继承,不允许多重继承
3.可以多重继承,一个类可以继承某一个类的子类,类B继承类A,类C继承类B,那么类C间接继承类A
4.子类继承父类所有的成员方法和成员变量,但是不继承父类的构造方法。在子类的构造方法中可以使用super语句(参数列表)调用父类的构造方法
5.如果子类的构造方法中没有显示的调用父类中的构造方法,也没有使用this关键字调用重载的其他构造方法,则在产生子类的实例对象时,系统默认调用父类无参数的构造方法
class Person {
public String name="unknow";
public int age=-1;
//无参构造
public Person(){
}
//有参构造
public Person(String name,int age){
this.name=name;
this.age=age;
}
public void getInfo(){
System.out.println("name:"+name+",age:"+age);
}
}
class Student extends Person{
//不用重写父类中的成员变量和成员方法
public String school="unknow";
//在调用这个构造函数之前先调用Person构造方法
public Student(){
//调用父类的构造函数
super();
// super("李四,18");
}
public Student (String name,int age,String school){
//this和super必须首先调用,否则会报错
super(name, age);
this.school=school;
}
public void getInfo(){
System.out.println("school:"+school+",name:"+name+",age:"+age);
}
public void study(){
}
}
class TextStudent {
public static void main(String []args){
//创建子类的对象
Student student=new Student();
student.name="zhangsan";
student.age=8;
//继承父类中的getInfo()
student.getInfo();
}
}
七、final关键字
1.在Java中声明类、属性、方法时,使用关键字final来修饰
2.final修饰的类不能被继承,方法不能被子类重写
3.final修饰的变量是常量,只能赋值一次
4.public ,static ,final共同标记常量时,这个常量就成了全局的常量
5.方法中定义的内置类只能访问该方法内的final类型的局部变量,final修饰的变量是常量,它的生命周期相超出方法运行的生命周期,将一个形参定义成final也是可以的,限定了我们在方法中修饰形式参数的值
//final修饰的类不能被继承
//final class Person
class Person {
//被final修饰的常量不能被修改,如果要是用使用就要创建实例,或者是加static
public final String x="ABC";
//final修饰的方法不会走下面的getInfo
//public final void getInfo()
public void getInfo(){
System.out.println("name:"+name+",age:"+age);
}
}
八、抽象类
1.定义:Java中可以定义一些不含方法体的方法,它的方法体的实现交给该类的子类根据自己的情况实现,这样的方法就叫抽象方法,包含抽象方法的类叫抽象类。
2.特点:•用abstract修饰的方法,没有方法体,叫抽象方法
•抽象类不能被实例化,也不能用new关键字去产生对象
•抽象方法只需要声明,不需要实现
•含有抽象方法的类必须别声明为抽象类,抽象类的子类必须覆盖所有的抽象方法后才能被实例化,否则这个子类还是个抽象类
•有抽象方法一定是抽象类或接口
•抽象类不一定有抽象方法,接口一定有抽象方法
•抽象类中可以有普通方法,静态方法,成员变量,接口只能有抽象方法和静态常量
九、接口(interface)
1.定义:因为有时程序无法准确地描述出类的行为,所以用接口来补充
2.特点:
⑴接口不能实例化(不能产生对象)
接口可以按照多态的方式,由具体的子类实例化,这也是多态的一种,接口多态。
⑵接口子类的特点
要么是抽象类,要么是普通类,如果是普通类,必须重写接口中的所有抽象方法。
⑶接口采用关键字interface定义。
⑷接口使用implements实现。
⑸如果一个类实现了某个接口,那么该类被称为实现类
⑹接口中的成员都是用public来修饰的,接口里的变量默认是用public static final标识的
十、对象的类型转换
1.子类对象可以自动转换为父类
2.父类转换成子类必须使用强制转换
3.instanceof操作符可以用它来判断一个实例对象是否属于一个类
十一、异常
1.定义:程序中遇到的非致命的错误,而不是编译时的语法错误,如程序要打开一个不存在的文件、网络、连接中断、操作数越界、装载一个不存在的类
2.Throwable继承层次结构,可见分成两大类Error和Exception:
Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题;发生于虚拟机自身、或者在虚拟机试图执行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误);属于不可查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。
Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:
•RuntimeException(运行时异常):由程序自身的问题导致产生的异常;如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常);属于不可查异常。
•非运行时异常:由程序外部的问题引起的异常;除了RuntimeException以外的异常,如FileNotFoundException(文件不存在异常);属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。
3.常见的异常处理机制有:
捕捉异常:由系统自动抛出异常,即try捕获异常->catch处理异常->finally 最终处理
抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。配合throws声明抛出的异常和throw抛出异常
自定义异常:继承Execption类或其子类
十二、多线程
1.进程
⑴定义:在多任务系统中,每个独立执行的程序,也就是进程,即“正在进行的程序”,我们现在使用的操作系统一般都是多任务的,即能够同时执行多个应用程序,实际情况是,操作系统负责对CPU等设备的资源进行分配和管理,虽然这些设备在某一时刻只能做一件事,但以非常小的时间间隔交替执行多个程序,就可以给人以同时执行多个程序的感觉
⑵一个进程中又可以包含一个或多个线程
2.线程
⑴一个线程就是一个程序内部的一条执行线索,如果要一程序中实现多段代码同时交替运行,就需产生多个线程,并指定每个线程上所要运行的程序代码段,就是多线程
3.后台线程与联合线程
⑴如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程。
⑵对于Java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程在运行,这个进程就会结束。
4.用Thread类创建线程
⑴要将一段代码在一个新的线程上运行,该代码应该在一个类的run函数中,并且run函数所在的类是Thread类的子类。倒过来看,我们要实现多线程,必须编写一个继承了Thread类的子类,子类要覆盖Thread类中的run函数,在子类的run函数中调用想在新线程上的运行的程序代码。
⑵启动一个新的线程,我们不是直接调用Thread的子类对象的run方法,而是调用Thread的子类对象的start(从Thread类继承到的)方法,Thread类对象的start方法将产生一个新的线程,并在该线程上运行该Thread的类对象中的run方法,根据面向对象的运行时的多态性,在该线程上实际运行的是Thread的子类(也就是我们写的那个类)对象中的run方法
⑶由于线程的代码段在run方法中,那么该方法执行完成以后,线程也就相应的结束了,因而我们可以通过控制run方法中循环的条件来控制线程的结束
5.后台线程和联合线程
⑴如果我们对某个线程对象在启动(调用start方法)之前调用了setDaemon(true)方法,这个线程就变成了后台线程。
⑵对java程序来说,只要还有一个前台线程在运行,这个进程就不会结束,如果一个进程中只有后台线程运行,这个进程就会结束
⑶pp.join()的作用是把pp所对应的线程合并到调用pp.join()语句的线程中
6.使用Runnable接口创建多线程
⑴适合多个相同程序代码的线程去处理同一资源的情况,把虚拟CPU(线程)同程序的代码,数据有效分离,较好的体现了面向对象的设计思想
⑵可以避免由于java的单继承特性带来的局限。我们经常碰到这样一种情况,即当我们要将已经继承了某一个类的子类放入多线程中,由于一个类不能同时有两个父类,所以不能用继承Tread类的方式,那么,这个类就只能采用实现Runnable
⑶当线程被构造时,需要的代码和数据通过一个对象作为构造函数实参传递进去,这个对象就是一个实现了Runnable接口类的实例
⑷几乎所有多线程应用都可以用Runnable接口方式
7.多线程在实际中的应用
网络聊天程序的收发
⑴如果一方从键盘上读取了数据并发送给了对方,程序运行到"读取对方回送的数据"并一直等待对方回送数据,如果对方没有回应,程序不能再做任何其他事情,这时程序处于堵塞状态,即使用户想正常终止程序运行都不可能,更不能实现"再给对方发送一条信息,催促对方赶快答应"这样的事情
⑵如果程序没有事先从键盘上读取数据并向外发送,程序将一直在"从键盘上读取数据"处堵塞,即使有数据从网上发送过来,程序无法到达"读取对方回送的数据"处,程序将不能收到别处先主动发送过来的数据
表记录的复制的中途取消
www服务器为每一个来访者都建立专线服务
8.多线程的同步问题
线程安全
线程安全就是当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。
同步代码块
•所谓代码块是指用“{}”括起来的一段代码,根据其位置和声明的不同,可以分为普通代码块、构造块、静态块、和同步代码块。
•如果在代码块前加上 synchronized关键字,则此代码块就成为同步代码块。
同步函数
同步函数:当一个函数是同步执行时,那么当该函数被调用时不会立即返回,直到该函数所要做的事情全都做完了才返回。
死锁问题
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
死锁的发生必须具备以下四个必要条件
①互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
②请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
③不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
④环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
9.进程间的通信
•wait:告诉当前线程放弃监视器并进入睡眠状态直到其他线程进入同一监视器并调用notify为止
•notify:唤醒同一对象监视器中调用wait的第一个线程,并于类似饭馆有一个空位后通知所有等候就餐的顾客中的第一位可以入座的情况
•notifyAll:唤醒同一对象监视器中调用wait的所有线程,具有最高优先级的线程首先被唤醒并执行。用于类似某个不定期的培训班终于招生满额后,通知所有学员都来上课的情况
10.线程生命周期的控制
先通过start()产生一个线程对象,这时线程并不是正真的执行,而是会进入Runnable()状态,然后由Scheduler(调度器/操作系统)来调度,正真开始执行的线程进入了Running()状态,如果这时run中的方法结束,线程就结束了;如果在线程运行的过程中,遇到了synchronized方法,就会发生堵塞,会在锁中发生停滞,直到得到对象的锁旗标之后,重新进入Runnable()状态(可执行状态),然后由调度器统一执行;如果得到wait()之后,会释放锁旗标,进入wait()的等待池中,遇到nitify()就会进入监视器的等待池中,直到得到对象的锁旗标之后,重新进入Runnable()状态(可执行状态),然后由调度器统一执行。
十三、JAVA API
1.概念
就是JDK中提供各种Java类,例如:Systom类
2.string类和stringBuffer类
•String类对象中的内容,一旦被初始化就不能再改变
•String类使用final修饰,所以不能被继承
•String的内存结构很特殊,在内存中有个字符串常量池,所有的字符串存放在字符串常量池中
•StringBuffer类用于封装内容可以改变的字符串
区别:
String:不可变字符串;频繁操作时,每次都需新开辟内存,极易造成内存浪费
StringBuffer:可变字符串、效率低、线程安全;执行速度慢
StringBuilder:可变字符串、效率高、线程不安全;执行速度快
(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用)。
•StringBuffer和StringBuilder类的对象能够被多次的修改,并且不产生新的未使用对象。
•StringBuilder类在Java5中被提出,它和StringBuffer之间的最大不同在于StringBuilder的方法不是线程安全的(不能同步访问)。
•由于StringBuilder相较于StringBuffer有速度优势,所以多数情况下建议使用StringBuilder类。
•然而在应用程序要求线程安全的情况下,则必须使用StringBuffer类。构造方法:
•String(byte[] bytes, int offset, int length) 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String
•equals 判断内容是否相等,区分大小写
•equalsIgnoreCase 判断内容是否相等,不区分大小写
•contains 是否包含子字符串
•isEmpty 判断字符串长度是否为0
•startsWith 判断是否以该字符串为前缀
•endsWith 判断是否以该字符串为后缀
•indexOf 判断int值对应的字符在该字符串中出现的位置||判断子字符串在该字符串中出现的位置
•copyValueOf 将字符数组转换成字符串,可以从off开始,到length结束
•lastIndexOf 获取最后一个字符的位置
•subString 截取
•getBytes 转换为byte[]数组
•tocharArray 转换成字符数组
•valueOf 将基本数据类型转换成字符串,byte数组或char数组也可以
•toLowerCase 转换成小写
•toUpperCase 转换成大写
•concat 拼接
3.基本数据类型的对象包装类
基本数据类型 | 基本类型的包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
4.集合类
•集合类用于储存一组对象,其中的每个对象称之为元素,经常会用到的有Vector ,Enumeration,Arraylist,Collection ,Set,List,Iterator的集合类和接口
•可将Java集合框架大致可分为Set、List、Queue 和Map四种体系
Set:代表无序、不可重复的集合,常见的类如HashSet、TreeSet
List:代表有序、可重复的集合,常见的类如动态数组ArrayList、双向链表LinkedList、可变数组Vector
Map:代表具有映射关系的集合,常见的类如HashMap、LinkedHashMap、TreeMap
Queue:代表一种队列集合
5.Properties类
•Properties类是Hashtable的子类
•增加了将Hashtable对象中的关键字和值保存到文件中和从文件中读取关键字和值到Hashtable对象中的方法
•如果要用Properties.store方法存储Properties对象中的内容,每个属性的关键字和值,都必须是String类型
6.时间和日期
SimpleDateFormat最常用几个类:Date、DateFormat和Calendar
Calendar类:•Calendar.add()方法
•Calendar.get()方法
•Calendar.set()方法
•Calendar.getInstance静态方法,获取日历对象
//格式化日期的
//pattern:日期的格式
//年(year):y表示,一般两位或者四位
//月(month):M表示,一般2位
//日(day):d表示,一般两位
//小时(hours):h表示,一般2位
//分钟(minutes):m表示,一般2位
//秒(seconds):s表示,一般两位
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
//SimpleDateFormat format = new SimpleDateFormat("yy-MM-dd:hh:mm:ss");
return format.format(calendar.getTime());
7.Time与TimeTask类
•schedule方法主要有如下几种重载形式:
schedule(TimeTask task,long delay)
schedule(TimeTask task,Date time)
schedule(TimeTask task,long delay,long period)
•TimeTask类实现了Runable接口,要执行的任务由他里面实现的run方法来完成