- JRE java运行环境,和java程序所需的核心类库,如果想要运行好一个开发好的java程序,计算机中只需要安装JRE即可
- JDK java开发工具包
- JDK是提供给java开发人员使用的,其中包含了java的开发工具也包含了JRE,所以安装了JDK,就不用单独安装JRE了,其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等
- 简单而言:使用JDK开发完成的java程序,交给JRE去运行
- 简而言之:
- JRE:JVM+类库
- JDK:JRE+JAVA的开发工具
- bin:该目录用于存放一些可执行程序
- javac.exe java编译器
- java.exe java运行工具
- javadoc.exe 文档生成工具
- db:db目录是一个小型的数据库,从jdk6.0开始,java中引用了一个新成员javaDB,这是一个纯java实现、开元的数据库管理系统,这个数据库不仅轻便,而且支持JDBC4.0的所有规范,在学习JDBC时候,不需要额外安装数据库软件,直接选择javaDB即可
- jre:java运行环境,此目录是java运行时环境的根目录,它包含java虚拟机,运行时类包,java应用启动器以及一个bin目录,但不包含开发环境中的开发工具
- inclide:由于JDK是通过C和C++实现的,因此在启动的时候需要引入一些C语言的头文件,该目录就是用于存放这些头文件的
- lib:library的缩写,意为java类库或库文件,是开发工具使用的归档包文件
- src.zip文件:src.zip为src文件夹的压缩文件,src中放置的是JDK核心类的源代码,通过该文件可以查看java基础类的源代码
System.out.println(0b100); //二进制表示形式前面加0b(b可以大写也可以小写)
System.out.println(0100); //八进制表示形式前面加0
System.out.println(100);
System.out.println(0x100); //十六进制表示形式前面加0x
- 基数:转换为X进制,基数就是X
- 权:自右向左从0开始数字依次递增编号
- 结果:系数*基数的全次幂
- 源码
- 二进制定点表示法,最高位为符号位,0表示正,1表示负;其余位表示数值大小
- 通过一个字节,也就是8个二进制位表示+7和-7
- 0(符号位) 0000111
- 1(符号位) 0000111
- 反码
- 正数的反码与其源码相同
- 负数的反码是对原码逐位取反,但符号位除外
- 补码
- 正数的补码与其原码相同
- 负数的补码是在其反码的末尾加1
- 隐式转换
- 小的数据类型和大的数据类型机型运算时,小的数据类型会自动转换为大的数据类型
- 强制转换
int x = 3; byte b = 4; b = (byte) (x + b); System.out.println(b); - 强制转换超出范围
byte b = (byte)(126+4); System.out.println(b); //-126 /* 130 -> 00000000 00000000 000000000 10000010 当去掉前三个8位的时候就成了 10000010 -> -126补码 10000001 -> 减1求-126反码 11111110 -> -126的原码 */ byte b2 = (byte)300; System.out.println(b2); //44 /* 300 -> 0000000 0000000 00000001 00101100 当去掉前三个8位的时候就成了 00101100 -> 44的补码 */
//看下面的程序是否有问题,如果有问题,请指出并说明理由
byte b1 = 3;
byte b2 = 4;
byte b3 = b1 + b2;
System.out.println(b3);
/*
解释1:byte和byte(short,char)进行运算的时候会提升为Int,两个int相加的结果也是int类型
解释2:b1和b2是两个变量,变量存储的值是变化的,在编译的时候无法判断里面具体得到值,相加有可能会超出bute的取值范围
*/
byte b4 = 3 + 4; //java编译器有常量优化机制
System.out.println(b4);
- 进行混合运算的时候,byte,short,char不会相互转换,都会自动提升为int,其他类型进行混合运算的是小的类型提升为大的
- byte,short,char -> int -> long ->float -> fouble
- long:8字节
- float:4字节
- 4字节是32个二进制位,一位是符号位,8位是指数位,23位是尾数位
//看下面得到程序是否有问题,有问题,请指出
short s=1; s=s+1; //编译出错,当short与int进行运算时,会提升为int
short ss=1;ss+=1; //正常 s = (short)(s+1);
- 数组的定义
//动态初始化
int[] arr = new int[5];
/*
左边:
int : 数据类型
[] : 代表的数组,几个中括号就是几位数组
arr : 合法的标识符
右边:
new : 创建新的实体或对象
int : 数据类型
[] : 代表的数组
5 : 代表数组的长度
*/
//静态初始化
/*
格式:数据类型[] 数组名 = new 数据类型[]{元素1,元素2};
简化格式:数据类型[] 数组名 = {元素1,元素2}; //声明和赋值必须在同一行
*/
//可行
int[] arr;
arr = new int[]{11,22,33,44,55};
//不可行,简写形式,声明和赋值必须在同一行
int[] arr2;
arr2 = {11,22,33,44,55};
- 整数类型:byte,short,int,long默认初始化值都是0
- 浮点类型:float,double默认初始化值都是0.0
- 布尔类型:boolean默认初始化值false
- 字符类型:char默认初始化值'\u0000'
- 内存划分:
- 栈:存储局部变量
- 堆:存储new出来的数组或对象
- 方法区:面向对象部分讲解
- 寄存器:给CPU使用
- 随着类的加载而加载
- 优先于对象存在
- 被类的所有对象共享
- 可通过类名调用
- 静态修饰的内容一般称其为:与类相关的,类成员,类方法
- 共享用静态,特性用非静态
- 在静态方法中是没有this关键字的
- 静态是随着类的加载而加载,this是随着对象的创建而存在
- 静态比对象先存在
- 静态方法只能访问静态的成员变量和静态的成员方法
- 静态只能访问静态
- 静态变量也叫类变量 成员变量也叫对象变量
- 所属不同
- 静态变量属于类,所以也称为类变量
- 成员变量属于对象,所以也称为对象变量或者实例变量
- 内存中位置不同
- 静态变量存储于方法区的静态区
- 成员变量存储于堆内存
- 内存出现的时间不同
- 静态变量随着类的加载而加载,随着类的消失而消失
- 成员变量随着对象的创建而存在,随着对象的小时而消失
- 调用不同
- 静态变量可以通过类名调用,也可以通过对象调用
- 成员变量只能通过对象名调用
- public 被jvm调用,所以权限要足够大
- static 被jvm调用,不需要创建独享,直接类名.调用即可
- void 被jvm调用,不需要有任何返回值
- main 只有这样写才能被jvm识别,main不是关键字
- string[] args:以前是用来接受键盘录入的
- 对工具类加入文档注释
- @author (作者信息)
- @version 版本信息
- @param 参数信息
- @return 返回值
- @param 参数名称,形式参数的变量名称
- 通过javadoc命令生成说明书
- javadoc -d 指定生成的文件目录 -author -version ArrayTool.java
- 局部代码块
- 在方法中出现;限定变量的生命周期,及早释放,提高内存利用率
public static void main(String[] args) { { int x = 10; //限定变量的生命周期 System.out.println(x); } } - 构造代码块
- 在类中方法外出现;多个构造方法中相同的代码存放到一起,每次调用构造都执行,并在构造方法之前执行
- 静态代码块
- 在类中方法外出现,加上了static修饰
- 用于类初始化,在加载的时候就执行,并且只执行一次,一般用于加载驱动
- 静态代码块优先于主方法之前执行
- 同步代码块(多线程)
-
好处
- 提高了代码的复用性
- 提高代码的维护性
- 让类与类之间产生了关系,是多态的前提
-
继承的弊端
- 累的耦合性增强了
-
开发的原则:高内聚,低耦合
-
耦合:类与类之间的关系
-
内聚:类自己的完整性、独立性
- Java值支持单继承,java支持多层继承
- 如果想用这个体系的所有功能用底层的类创建对象
- 如果想看这个体系的共性功能,看最顶层的类
- 子类只能继承父类所有非私有的成员(成员方法和成员变)
- 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类的构造方法
- 不要为了部分功能而去继承
- 同名的变量
- 子父类出现同名的变量只是在讲课中举例子有,在开发中是不会出现这种情况的
- 子类继承父类就是为了使用父类的成员,那么如果定义了同名的成员变量就没有意义了
- this代表当前对象的引用
- super代表当前对象父类的引用
- this和super在使用上的区别
- 调用成员变量
- this 可调用本类的成员变量,也可以调用父类的成员变量
- super 调用父类的成员变量
- 调用构造方法
- this(...) 调用本类的构造方法
- super(...) 调用父类的成员方法
- 调用成员方法
- this 可调用本类的成员方法,也可以调用父类的成员方法
- super 调用父类的成员方法
- 调用成员变量
- 子类中所有的构造方法默认都会访问父类中空参的构造方法
- 因为子类会继承父类中的数据,可能还会使用父类的数据
- 所以,子类初始化之前,一定要先完成父类的初始化
- 其实,没一个构造方法的第一条语句默认都是super() Object类第最顶层的类
- 父类中没又无参构造,子类怎么办
- super(...)解决,在子类中用super访问父类的有参构造
- this(...)解决,在子类无参构造里用this(..)访问子类有参构造,进而访问父类有参构造
- 父类中私有方法不能被重写,因为私有方法根本无法继承
- 子类重写父类方法时,访问全向不能更低,最好一致
- 父类静态方法,子类也必须通过静态方法进行重写,其实算不上重写(多态讲解)
- final 最终的
- final修饰特点
- 修饰类,类不能被继承
- 修饰变量,变量就成了常量,只能赋值一次
- 修饰方法,方法不能被重写
- 基本类型,是值不能被改变
- 引用数据类型,是地址值不能被改变,对象中的属性可以改变
- 显示初始化
final int num = 10; //显示初始化,成员变量的默认初始化值是无效值
- 在对象构造时初始化值
final int num;
public Demo(){
num = 10;
}
- 要有继承关系
- 要有方法重写
- 要有父类引用指向子类对象
- 成员变量
- 编译看左边(父类),运行看左边(父类)
- 成员方法
- 编译看左边(父类),运行看右边(子类),动态绑定
- 静态成员方法
- 编译看左边(父类),运行看左边(父类)
- 静态和类相关,算不上重写,所以,访问还是左边的,只有非静态的成员方法,编译看左边,运行看右边
父类引用指向子类对象是向上转型
- 好处
- 提高了代码的维护性(继承保证)
- 提高了代码的拓展性(多态保证)
- 可以当做形式参数,接受任意类型的子类对象
- 弊端
- 不能使用子类特有的属性和行为
- 抽象类特点
- 抽象类和抽象方法必须用abstract关键字修饰
- abstract class 类名{}
- public abstract void eat();s
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类或接口
- 抽象类不能实例化,按照多态的方式,有具体的子类实例化,这也是多态的一种,抽象类多态
- 抽象类的子类,要么是抽象类,要么实现抽象类中所有抽象方法
- 抽象类和抽象方法必须用abstract关键字修饰
-
抽象类的成员特点
- 成员变量:既可以是变量,也可以是常量,abstract不能修饰成员变量
- 有构造方法,用于子类访问父类数据的初始化
- 成员方法:既可以是抽象的,也可以说非抽象的
-
抽象类的成员方法特性:
- 抽象方法,强制要求子类实现
- 非抽象方法,子类继承,提高代码复用性
-
一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
- 可以,这么做的目的只有一个,就是不让其他类创建本类对象,交给子类完成
-
abstract不能和final,static,private共存
- 被abstract修饰的方法没有方法体
- 被static修饰的可以用类名.调用,但是类名.调用抽象方法是没有意义的
- 被abstract修饰的方法强制子类重写
- 被final修饰的方法不让自类重写,所以他两是矛盾的
- 被abstract修饰的方法是为了让子类看到并强制重写
- 被private修饰不让子类访问,所以矛盾
- 接口的子类
- 可以是抽象类,但是意义不大
- 可以是具体类。但是要重写接口中所有的抽象方法
- 接口中所有方法都可以是抽象的
- 成员变量:只能是常量,并且是静态的公共的
- 默认修饰符:public static final
- 建议手动给出修饰符
- 构造方法:接口没有构造方法
- 成员方法:只能是抽象方法
- 默认修饰符:public abstract
- 建议手动给出修饰符
- 类与类
- 继承关系,只能单继承,可以多层继承
- 类与接口
- 实现关系,可以单实现,也可以多实现
- 并且还可以继承一个类的同时实现多个接口
- 接口与接口
- 继承关系,可以单继承,也可以多继承
- 抽象类:
- 成员方法:可以是变量,也可以是常量
- 构造方法:有
- 成员方法:可以抽象,也可以非抽象
- 接口:
- 成员变量:只可以是常量,静态
- 成员方法:只可以抽象
- 类与类
- 继承,单继承
- 类与接口
- 实现,单实现,多实现
- 接口与接口
- 继承,单继承,多继承
- 抽象类:被继承体现的是"is a"的关系,抽象类中定义的是该继承体系的共性功能
- 接口 :被实现体现的是"like a"的关系,接口中定义的是该继承体系的扩展功能
本类 同一个包下(子类和无关类) 不同包下(子类) 不同包下(无关类)
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
内部类访问特点:
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
- 外部类名.内部类名 变量名 = 外部类对象.内部类对象
class Demo1_InnerClass {
public static void main(String[] args){
Outer.Inner oi = new Outer().new Inner(); //创建内部类对象
}
}
class Outer {
class Inner {
public void method(){
System.out.println("Hello World!");
}
}
}
public class Test {
public static void main(String[] args) {
// Outer.Inner oi = new Outer().new Inner();
// oi.method();
Outer o = new Outer();
o.print();
}
}
class Outer {
private int num = 10;
private class Inner {
public void method(){
System.out.println("Hello World!");
}
}
public void print(){
Inner i = new Inner();
i.method();
}
}
public class Test {
public static void main(String[] args) {
//外部类名.内部类名 对象名 = 外部类名.内部类对象
Outer.Inner oi = new Outer.Inner();
oi.method();
Outer.Inner2.print();
}
}
class Outer {
static class Inner {
public void method(){
System.out.println("method");
}
}
static class Inner2 {
public static void print(){
System.out.println("print");
}
}
}
public class Test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
class Outer {
//内部类之所以能获取到外部类的成员,是因为他能获取到外部类的引用 -> 外部类名.this
public int num = 10;
class Inner {
public int num = 20;
public void show(){
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
- 局部内部类访问局部变量必须用final修饰
- 局部内部类在访问它所在的方法中的局部变量时,局部变量必须用final修饰,为什么?
- 因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和它的方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失 ,那么如果局部内部类对象还没有马上消失想用这个局部变量,而这个变量已经没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用,但是jdk1.8没有这个要求
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
class Outer {
public void method(){
final int num = 10;
class Inner {
public void print(){
System.out.println(num);
}
}
Inner i = new Inner();
i.print();
}
}
- 匿名内部类是局部内部类的一种,因此匿名内部类必须写在方法中
- 本质:
- 是一个继承了该类或者实现了该接口的子类匿名对象
//非匿名的内部类
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
interface Inter {
public void print();
}
class Outer {
class Inner implements Inter {
public void print(){
System.out.println("print");
}
}
public void method(){
Inner i = new Inner();
i.print();
}
}
//匿名内部类
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
interface Inter {
public void print();
}
class Outer {
class Inner implements Inter {
public void print(){
System.out.println("print1");
}
}
public void method(){
// Inner i = new Inner();
// i.print();
new Inter(){ //实现Inter接口,Inter的子类对象
public void print() {
System.out.println("print");//重写抽象方法
}
}.print();
}
}
public class Test {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
interface Inter {
public void show1();
public void show2();
}
//匿名内部类最好只针对重写一个方法的时候使用
class Outer {
public void method(){
Inter i = new Inter(){ //实现Inter接口,Inter的子类对象,父类引用指向子类对象,弊端:无法使用子类特有的方法
public void show1() {
System.out.println("show1");
}
public void show2() {
System.out.println("show2");
}
/*public void show3() {
System.out.println("show3");
}*/
};
i.show1();
i.show2();
// i.show3(); //匿名内部类是不能向下转型的,因为没有子类类名
}
}
public class Test {
public static void main(String[] args) {
//如何使用PersonDemo中的method方法呢
PersonDemo pd = new PersonDemo();
pd.method(new Person(){ //匿名内部类当做参数传递(本质把匿名内部类当做一个对象)
public void show() {
System.out.println("show");
}
});
}
}
//这里写抽象类,接口都行
abstract class Person {
public abstract void show();
}
class PersonDemo {
public void method(Person p){
p.show();
}
}

