JAVA基础知识

JAVA的编译过程

.java (用javac.exe编译) ->  .class(字节码文件,不是二进制文件,否则计算机可以直接运行)  ->  类装载器  ->  java虚拟机(JVM)  ->  操作系统

.class文件生成后,.java源文件被删除不影响运行

javac.exe是编译程序,java.exe是运行程序

/** 
*
*
*/  这种注释在编译时会被放入帮助说明书内

一个.java源文件只能有一个public的类,并且必须与源文件同名

每一个class中都可以有一个main方法

JAVA标识符

常量名:全大写
变量名,方法名:首字母小写,后面每个单词首字母大写
类名,接口名:首字母大写,后面每个单词首字母大写

java中局部变量声明后必须赋值才能访问,否则编译报错;而成员变量系统则会自己赋值

成员变量没有手动赋值时,系统自动赋值为:

byte,short,int,long0
float,double0.0
boolean  false
char \u0000
引用数据类型 null

java访问变量符合就近原则

public static class
{
    public static void main(String[] args)
    {
        System.out.println(i);
    }
    static int i =100;
}
这样也可以打印出100

基本数据类型中和C语言不一样的地方

布尔类型为 boolean ,只有 true  false ,不能用0和1表示
整数型多了一个 byte 占一个字节的整数位
char 占两个字节

Unicode编码

一种全球通用的的文字
分为:utf-8(常用),utf-16,utf-32
Java采用的是Unicode编码,因此标识符可以用中文
JDK中自带的native2ascii可以把中文转移为unicode编码

long sum = 1111111111222;
如果这样编译会报错,因为1111111111222会被系统当做一个整型来处理,而整型缺省为int型,显然该数字大于int型最大值,因此会报错
解决方法是在数字末尾加上L,告诉编译器是一个long类型的值
long sum = 1111111111222L;

如果long类型要赋值到int类型,会出现精度丢失,因此要使用强制类型转换,规则与C一样

强制类型实现原理

long a = 2147483648L ;
int b = (int)a ;
最后b会等于 -2147483648

因为2147483648  B=00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000
int只能有4个字节,因此: 10000000 00000000 00000000 00000000 = -214743648

java中所有浮点型默认被当做double类型来处理,如果要用float型,则在末尾添加F

java输入数据

java.util.Scanner  str = new java.util.Scanner(System.in);
String strname = str.next();
int intname = str.nextInt(); 

for(初始化表达式;布尔表达式;更新表达式)
while(布尔表达式)
注意:一定是布尔表达式,不像C语言一样,可以是其他值

continue不一样的用法

continue 循环名称
myFor: for(int i=0;i<10;i++){
    if(i==5){
    continue myFor;
    }
    System.out.print(i+"\t");
}

不是void返回值类型的函数必须以return结尾,并且return后不能有任何多余的语句

void 里面可以有return语句,但是不可以有返回值,可以用return语句来结束函数

JVM中内存分为这样三块常用的内存(还有其他的)

1、方法区内存( 静态变量和代码 )
2、堆内存( 实例化对象时存储,字符串 (因为字符串本质是自定义类) )
3、栈内存( 方法调研时压栈 (方法的局部变量) )

封装

有static关键字的方法调用:类名.方法名(),意味着要同构类来调用
无static关键字的方法调用:引用.方法名()


访问控制权限修饰符

public在任意位置都可以访问
protected同包下可以访问,不同包下需要继承才能访问
缺省同包下可以访问
private只有在本类中可以访问

类只能用public或缺省来修饰(内部类除外)

构造函数

对于构造方法来说,不需要返回值类型,甚至 void 也不能有
构造函数名要与类名保持一致
构造方法调用方式:new 构造方法名(实参列表);
构造方法也可以重载(但是构造函数是不能被覆盖的

this指针里存储类自己的地址,所以this指针指向自身
this也可以用于函数的重载上,例如:

public Date(String year)
{
    this.year = year;
}

public Date()  //当调用这个函数时将年份改为默认的1970年
{
    this(1970);
}

如果这个特征是类的属性,而不是每个实例的属性,则用static
例如,中国人这个类中,国籍大家都想同,因此国籍应该是静态变量
方法也是类似

static的方法或属性在类加载时就执行,并且只能执行一次
静态代码块:在类加载时刻执行,并且也只有一次(用于日志的记录)

继承

[修饰符列表] class 类名 extends 父类{}
私有的不继承,构造方法不继承,其他数据都可以被继承
所有类都默认继承Object类

重写时,权限只能更高不能更低,抛出异常只能越多不能越少

如果父类的方法是静态的,可以重写,但是重写时还得是静态的

多态

分为向上转型(自动转换)和向下转型(需要强制类型转换符)


向上转型:Animal a = new Cat();
对于JAVA程序,分为编译阶段和运行阶段

public class human
{
    public void run()
    {
        System.out.println("running");
    }
}
public class runningplayer extends human
{
    public void run()
    {
        System.out.println("跑步!");
    }
    public void fight()
    {
        System.out.println("fighting!");
    }
}
public class Message
{
    public static void main(String[] args)
    {
        human i = new runningplayer();
        i.run();
    }
}


在编译阶段因为i的引用类型是human类型,而human类型中有run方法,因此编译通过,这个过程我们称为静态绑定
在运行阶段,因为实际创建的对象时runningplayer类型,因此最后 i.run() (不论有没有重写)的结果是 跑步!,这个过程叫做动态绑定,或者运行阶段绑定


向下转型: runningplayer c = (runnningplayer) i; 只有当i不得不使用runningplayer才有的方法fight时,我们才会向下转型

instanceof函数

用于判断某个实例是否属于某个类,是则返回 true 不是则返回 false
例如:a3 instanceof Cat    //a3 是否是猫

final关键字

被final修饰的类无法被继承
被final修饰的方法无法被覆盖
被final修饰的变量一旦赋值后,不可重新赋值
被final修饰的实例变量也不可重新赋值
被final修饰的引用,不能再指向其他对象(但其中指向的内存的内容是可以更改的)
当static final一起联用我们就叫做常量,注意常量名全大写

package 和 import

定义package:在java源文件第一行上编写
package只能编写一个语句:package 包名; (包名:公司域名倒序.项目名.模块名.功能名)
包名也是标识符,全部小写,语句结束有分号
包用于存放多个class文件,手动创建文件夹,一个包就是一个文件夹
包的路径就是:公司域名倒序\项目名\模块名\

编译时 javac java源文件路径
运行时 java 包的路径

或者 javac -d . *.java     编译当前目录下所有java文件,会自动生成包路径
-d 后加编译之后存放路径

import 包名 (要写在package语句后,class语句前)
java.lang.* 不需要手动引入,系统自动引入


super关键字

super只能放在构造方法的第一行,当没有写的时候,系统默认有一个super()无参数的构造方法
继承中的构造方法,一定(100%)要先创建了父类,才能创建子类,而super()就是用来创建父类用的
当有this()函数时,可能会执行,this()的构造方法,但最后super()函数一定会运行一次
super()相对于当前对象,一定是在 "栈顶部"
super()和this()一样不能出现在static方法内
super.属性(当父类和子类有相同的属性名字,在子中访问父类的属性时使用)

抽象类

抽象类无法实例化,无法创建对象(因为抽象类的对象对应的是类,而类本身不存在,所以抽象类无法创建对象)


定义:权限访问修饰符 abstract class  类名 {}


抽象类是用来被子类继承的,也可以被抽象类继承
finalabstract 不能联合使用


abstract 方法();       特点:没有方法体 


抽象方法只能出现在抽象类中,抽象类不一定要有抽象方法


子类继承抽象类,必须实现对抽象类的所有抽象方法进行覆盖(实现)

接口

权限访问修饰符 interface 接口名{};


接口支持多继承,可以继承多个接口


接口里只包含常量和抽象方法
因此,接口中的方法可以省略public abstract,常量可以省略public static final

类和类之间叫做继承(extends),类和接口之间叫做实现(implements)

当即有继承又有接口时,extend在前,implements在后

抽象类有构造方法,接口没有构造方法
接口比抽象类更常用,接口一般都是对“行为”的抽象(功能)

深克隆和浅克隆

浅克隆

当有一个order1,其中包含一个name属性和item对象
order2 = order1.clone();
如果改变order2.name是不会改变order1.name的,但是如果改变order2.item,则会影响order1.item

因为浅克隆,不会克隆对象 引用的 对象
而深克隆可以

内部类

分为:静态内部类,实例内部类,局部内部类

匿名内部类是因为这个类没有名字

m.sun(new Compute(){
    System.out.println("实现内部类");
    },200,100
)

用匿名内部类,在方法中直接声明并且实现接口

数组

静态初始化
引用数据类型[] 数组名 = {100,200,300,400};

动态初始化
引用数据类型[] 数组名 = new int[10];    //默认值为0

native 关键字表示函数底层使用的是C++实现方法

数组拷贝是将对象的地址重新拷贝一份,指向的还是同一个地址,而不是重新创建一个对象

枚举类型

枚举类型一般是用来作为方法返回值
枚举也是一种数据类型,编译后也是生成class文件

public enum R{Success,False,Continue}

低版本的JDK,switch只支持Int和char
高版本的JDK,switch支持String和枚举

UML是一种统一建模语言,图标式语言(画UML图的都是软件设计人员,软件构架师,系统分析师)

异常

异常在JAVA中以类的形式存在,每一种异常都可以创建对象
Error 一旦出现,JAVA程序是一定要退出的;Exception 就可以处理
Exception 的子类 ExceptionSubClass(编译时异常(也是在运行阶段)), RuntimeException(运行时异常)

异常处理方式

1. 在方法声明上使用 throws 关键字,抛给上一级
2. 使用 try catch 语句进行异常捕捉

  1. 方法名() throws 异常名称{};    //一般main方法上不适应throw,因为这样抛给JVM就直接终止程序了,异常处理没有意义
  2. try{
    运行代码
    }
    catch(异常名称 异常标识符){
    异常处理
    }
    finally{}

方法中异常抛出后的代码是不会被执行的,但是catch后的代码会继续执行,这样就保证了代码的健壮性(保证了服务器不会宕机)
异常信息不是在程序内一起输出的,而是由某个线程异步输出
try{}catch{}语句中catch可以有多个,而且必须从小到大,子类在前,父类在后
JAVA8之后catch()括号里可以写 || 运算符
finally子句中的语句是一定会执行的,不管try和catch有没有执行
如果try语句中有return语句,会先运行finally子句再运行return,return语句一定是最后执行的
如果try语句中有System.exit(0)语句,finally子句就不会运行了

Java中自定义异常

1.编写一个类继承 Exception RuntimeException.
2.提供两个构造方法一个无参一个有参String(有参的构造方法只要用super的就行了)

重写父类方法,子类只能比父类抛出更少的异常;假如父类不抛出异常,子类可以抛出RuntimException

集合

集合不能直接存储基本数据类型,也不能直接存储对象;只能存储引用或者说地址
集合分为两大类:一类是以 单个 的方式存储元素(Collection),另一类是以 键值对 的方式存储元素(Map)

类型底层数据结构安全性说明
ArrayList数组非线程安全

LinkedList

双向链表非线程安全
Vector数组线程安全效率较低
Hash哈希表底层new了一个HashMap集合,HashMap集合底层是用哈希表实习的
TreeSet二叉树

new了一个TreeMap集合,TreeMap底层是用二叉树实现的

(存储的数据可以自动按照大小排序)

Map

以键值对的方式存储元素,所有的Map集合都是无序不可重复的

(无序是指没有下标)

HashMap哈希表非线程安全
Hashtable哈希表线程安全现在用的较少
Properties线程安全key和value只支持String类型

Map集合不能使用Iterator,在Collection下的子类才可以用

泛型

没有使用“泛型”之前,Collection中可以存储Object的所有子类型,使用之后就只能存某个具体的类型

用于指定集合中存储的数据类型
List<数据类型> myList = new ArrayList<数据类型>();
JDK高本版之后,后面的new的泛型的数据类型可以不写,JDK拥有自动类型推动,这样的表达式称为钻石表达式

泛型可以自定义

foreach语句

专门用于数组的遍历

for(int data : array){
    System.out.println(data);
}

java.io类

以Stream结尾的都是字节流,以er结尾的都是字符流

转换流:(将字节流转换为字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter

Project的根目录就是IDLE的默认当前路径

序列化(Serialize)就是把Java对象存储到硬盘文件中
反序列化(DeSerialize)把硬盘中的数据恢复到内存上形成Java对象

序列化的类要实现Serializable接口
Java中有两种接口,一种是普通接口,另一种是标志接口
Serializable就是标志接口,用于给JVM识别,JVM会自动生成序列化版本号

transient(游离的)关键字
用于表示改属性或者方法不参与序列化

JVM区分类靠的就是 类名序列化版本号
序列化版本号的缺陷:生成了版本号后不能修改该类的代码,若修改了,之前的版本号的数据就废了因此我们可以手动生成一个序列化版本号(尽量做到独特)

private static final long serialVersionUID = ........;

经常要改变的信息写在文件里,这样程序再去读取文件,这样程序就不需要反复编译,服务器也不需要重启,这样的文件叫做 配置文件
并且内容格式为:key = value 时,我们叫做属性配置文件
java中属性配置文件建议以 .properties 结尾,在配置文件中#是注释
如果key重复了,value会自动覆盖

多线程

多线程三大特性

  • 原子性,可见性,有序性

进程间内存不共享
线程在Java中,方法区和堆内存共享,栈内存独立(一个线程一个栈

实现多线程有两种方法:
方法一:
编写一个类,继承java.lang.Thread类,重写run方法(run()方法就是类似主线程中的main()方法)
在主线程中创建线程对象,然后再用 对象.start() 就可以启动该线程了
start()方法的作用是在JVM中开辟一个新的栈空间,开辟完这句代码瞬间就结束了
线程启动后会自动调用run()方法,而且run()在栈底

方法二:
编写一个类,实现java.lang.Runnable接口,再将该对象封装成一个线程类
Thread t = new Thread(new MyRunnable());

第二种比第一种更加常用,因为类实现了接口还可以去继承其他类
当线程没有设置名字时,线程默认名字为Thread-0,Thread-1,Thread-2
Thread的run()方法没有实现Throwable,因此我们写的run()方法不能抛出比父类更多异常,只能try和catch

t.stop() 可以终止一个进程,但是已过时了,因为会造成资源丢失
现在都用t.run = false这种信号量的方法

java中的优先级
默认为5,最低为1,最高为10

synchronized(){
    线程同步代码块;
}

括号内填入共享资源,可以是对象
同步代码块越小,效率越高

synchronized如果写在实例方法上,锁的一定是this,不灵活,而且同步范围扩大了,效率降低(保证实例变量安全)
如果在静态方法上使用synchronized,那么就是类锁,类所只有一把(保证静态变量安全)
synchronized在开发中最好不用嵌套使用,容易死锁

线程分为两种:1、用户线程    2、守护线程
守护线程一般是一个死循环,只要用户线程结束,一般守护线程会自动结束

实现线程的第三种方法!(JDK8之后)实现Callable接口,可以获取一个线程的执行结果
要引入java.util.concurrent.FutureTask包
创建一个“未来任务类”对象
 

FutureTask task = new FutureTask(new Callable(){});
//括号内要传入一个Callable接口实现对象,也可以是匿名内部类

Thread t = new Thread(task);        //创建线程对象
task.get();                         //获取t线程的执行结果

定时器

java.util.Timer类可以直接拿来用
但在实际开发中用最多的是Spring框架中的SpringTask框架

wait和notify方法(Object类自带的)

Object o = new Object();
o.wait();        //让对象o进行无限等待,直到被notify唤醒为止

变长参数

public static void m(int... args){}        //可变长度参数
可变长度参数只能出现一个,而且在参数列表最后面,可变长度参数可以看成一个数组

反射机制

反射机制可以操作字节码文件

java.lang.reflect

java.lang.Class                                代表字节码文件
java.lang.reflect.Method                 代表方法字节码
java.lang.reflect.Constructor         代表构造器字节码
java.lang.reflect.Field                      代表属性字节码

String s = "abc";
Class x = s.getClass();
Class c = Class.forName("java.lang.String");    //forName的执行会导致类加载(类加载时,静态代码块执行)
System.out.println(x==c);    //返回true
Class y = String.class;
System.out.println(y==c);    //返回true

通过反射机制,可以在不改变java源代码的基础之上,做到不同类型的对象实例化

原始路径方式对于代码来说可移植性差

String path = 
Thread.currentThread().getContextClassLoader().getResource("FileName").getpath();
//获取当前线程,获取当前线程下的类加载器,从类的跟目录开始加载资源FileName,获取它的路径


InputStream in = 
Thread.currentThread().getContextClassLoader().getResourceAsStream("FileName");
//以流的方式返回

FileName为src下的相对路径

资源绑定器(properties文件必须在类路径下)

import java.util.ResourceBundle;
ResourceBundle bundle = ResourceBundle.getBundle("FileName");
String className = bundle.getString("key");

类加载器(启动类加载器,扩展类加载器,应用类加载器)
(父加载器)启动类加载器会加载:jre\lib\rt.jar (java中最核心的类库)
(母加载器)扩展类加载器会加载:jre\lib\ext\*.jar 
应用类加载器会加载:classpath下
java中为了保证类加载的安全,是用来双亲委派机制,优先重双亲加载器中加载(先父后母)

反射Field

Field[] fields = studentClass.getFields();            //获取的是公开的属性
Field[] fields = studentClass.getDeclaredFields();    //获取所有属性
Field[0].getName();                                   //获取属性名
Field[0].getType();                                   //获取属性类型
Field[0].getType().getSimpleName();                   //获取简洁的属性类型
int i = Field[0].getModifiers();                      //获取修饰符数字(数字是修饰符枚举类型代号)
Modifier.toString(i);                                 //将数字类型转换为修饰符字符串
Field no = studentClass.getDeclaredField("FieldName");    //获取名为FieldName属性
no.set(对象,value);                                       //给对象的no属性赋值value
no.get(对象);                                             //获取对象的no属性值value

反射机制缺点:no.setAccessible(true);会打破封装,可能对安全性造成影响

反射Method

Class u = Class.forName("ClassName");
Object obj = u.newInstance();                    //实例化一个对象
Method[] methods = u.getDeclaredMethods();       //获取所有方法
methods.getReturnType();                         //获取返回类型
Class[] p = methods[i].getParameterTypes();    //获取参数列表

Method fun = u.getDeclaredMethod("funName",int.class,String.class);
//括号里填方法名和参数列表里的参数类型

fun.invoke(obj,1,"abc");                         //调用obj对象的fun方法,将参数1和"abc"传入

反射Constructor

Class v = Class.forName("ClassName");
Constructor constructors = v.getDeclaredConstructors();                //获取所有构造方法
constructors[i].getModifiers();        //获取构造
Constructor con = c.getDeclaredConstructor(int.class,String.class);    //获取指定的构造方法
con.newInstance(110,"jackson");        //实例化对象

反射父类和接口

Class superclass = v.getSuperclass();      //获取父类
Class[] interfaces = v.getInterfaces();    //获取接口列表

注解

注解编译后也是xxx.class文件,是一种引用数据类型
理论上注解可以出现在任何地方

格式:[修饰符列表] @interface 注解类型名{}

@Deprecated 
//用@Deprecated注释的程序元素,不鼓励程序员使用,通常因为有更好的选择或者它很危险//表示该元素已过时

@Override 
//表示重写父类一个方法

@SuppressWarnings 
//指示应该在注释元素中取消指定的编译器警报

元注解是注解里的注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target 
//用来标注“被标注的注解”可以出现在哪些位置上

@Retention 
//用来标注“被标注的注解”最后保存在哪里

注解中的属性

String name() default "abc";    //看着像是一个方法,但其实是一个属性,默认值为abc

在注解中有属性的,在写注解时必须给属性赋值(除非有默认值)
当注解中只有一个属性名并且是value时,在给属性赋值时value属性名可以省略
注解中的属性可以是数组类型

@Retention(RetentionPolicy.RUNTIME)           //这样的“被注解元素”可以被反射
c.isAnnotationPresent(MyAnnotation.class);    //判断是否存在MyAnnotation注解
MyAnnotation ca = c.getAnnotation(MyAnnotation.class);        //获取注解对象
ca.属性名();                                  //获取注解中的属性值

类中的属性默认是私有的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值