主要是因为Java中有一种机制:
自动垃圾回收机制(GC机制)
JVM负责调度GC机制。程序员不需要干涉
java语言是健壮的,相对于c语言来说,c语言没有Java健壮。
Java不容易导致内存的泄漏。
C++或者c语言使用不当时很容易导致内存泄漏。
可移植性/跨平台
java语言只要编写一次,可以做到到处运行。
例如: java程序编写完之 后,可以运行在windows操作系统上,
不需要做任何改动可以直接运行在Linux操作系统上,同样也
可以运行到MaCOS_上面。
一次编写,到处运行。( 平台改变了,程序不需要改。)
JVM这种机制实现了跨平台,那么这种机制优点和缺点分别是什么?
优点:一次编写到处运行,可以跨平台。
缺点:麻烦。对于运行java程序来说必须先有一个 JVM。
就像你要想在网页上看视频,你必须先安装一一个 flash是一样的。
JDK: Java开发工具箱
JRE:java运行环境
JVM: java虚拟机
JDK包括JRE,JRE包括JVM。
JVM是不能独立安装的。
JRE和JDK都是可以独立安装的。
有单独的JDK安装包。
也有单独的JRE安装包。
没有单独的JVM安装包。
字节码文件不是二进制文件。
如果是二进制的话,就不需要JVM了。
因为操作系统可以直接执行二进制
编译期:(可以在windows上)
如果xxx.java文件中编写的源代码违背了语法规则,那么编译器会报错,编译器
报错之后class文件是不会生成的,只有编译通过了才会生成class字节码文件。
并且一个java源文件是可以生成多个class文件的。(编译实质上是检查语法)
运行期(JRE在起作用):(可以在windows上,也可以在其他的OS上。)
将生成的class文件复制到指定的系统、将字节码文件将给JVM,JVM解释器把字节码文件
转换成为二进制文件,交给OS操作系统,操作系统会执行二进制码和硬件进行交互。
总结: 启动JVM虚拟机,
JVM启动类加载器classloader去找到对应的字节码文件,
文件装载到JVM当中,JVM启动“解释器”将字节码解释为“101010000…”这种二进制码,操作系统执行二进制码和硬件交互。
第一步:会先启动JVM(java虚拟机)
第二步:JVM启动之后,JVM会去启动“类加载器classloader”
类加载器的作用:加载类的。本质上类加载器负责去硬盘上找“类”对应的“字节码”文件。
假设是“java HelloWorld”,那么类加载器会去硬盘上搜索:HelloWorld.class文件。
假设是“java Test”,那么类加载器会去硬盘上搜索:Test.class文件。
第三步:
类加载器如果在硬盘上找不到对应的字节码文件,会报错,报什么错?
错误: 找不到或无法加载主类
类加载器如果在硬盘上找到了对应的字节码文件,类加载器会将该字节码
文件装载到JVM当中,JVM启动“解释器”将字节码解释为“101010000…”这种
二进制码,操作系统执行二进制码和硬件交互。
默认情况下,类加载器去硬盘上找“字节码”文件的时候,默认从哪找????
默认情况下类加载器(classloader)会从当前路径下找。
此处应该有疑问,你可以提出哪些问题????
能不能给类加载器指定一个路径,让类加载器去指定的路径下加载字节码文件。
答案:可以的。但是我们需要设置一个环境变量,叫做:classpath
classpath是一个环境变量,是给谁指路的?
答案:是给“类加载器”指路的。
classpath环境变量不属于windows操作系统,classpath环境变量隶属于java。。
一定要理解classpath环境变量的作用是什么?
是给类加载器指路的。
在没有配置环境变量classpath的时候,默认从当前路径下加载。
如果配置了环境变量classpath的话,就只能从指定的路径下加载了。
数据类型有什么用?
数据类型用来声明变量,程序在运行过程中根据不同的数据类型分配不同大小的空间。
第一种:基本数据类型
基本数据类型又可以划分为4大类8小种
第一类:整数型
byte(1),short(2),int(4),long(8)
第二类:浮点型
float(4),double(8)
第三类:布尔型
boolean(1)
第四类:字符型
char:(2)
8小种:
byte,short,int,long
float,double
boolean
char
第二种:引用数据类型
字符串型String属于引用数据类型。
String字符串不属于基本数据类型范畴。
java中除了基本数据类型之外,剩下的都是引用数据类型。
引用数据类型后期面向对象的时候才会接触。
第一条:八种基本数据类型中,除 boolean 类型不能转换,剩下七种类型之间都可以进行转换;
第二条:如果整数型字面量没有超出 byte,short,char 的取值范围,可以直接将其赋值给byte,short,char 类型的变量;
第三条:小容量向大容量转换称为自动类型转换,容量从小到大的排序为:
byte < short(char) < int < long < float < double,其中 short和 char
都占用两个字节,但是char 可以表示更大的正整数;
第四条:大容量转换成小容量,称为强制类型转换,编写时必须添加“强制类型转换符”,
但运行时可能出现精度损失,谨慎使用;
第五条:byte,short,char 类型混合运算时,先各自转换成 int 类型再做运算;
第六条:多种数据类型混合运算,各自先转换成容量最大的那一种再做运算;
算术运算符:、+ 、- 、* 、/、 % 、++ 、–
关系运算符:>、 >=、 < 、<=、 ==、 !=
逻辑运算符:& | ! && ||
赋值运算符:= += -= *= /= %=
三目运算符:布尔表达式 ? 表达式1 : 表达式2 true取1false取2
字符串连接运算符:+
逻辑运算符之 短路和短或
表达式A && 表达式B 当A为false 就不判断表达式B
表达式A || 表达式B 当A为true 就不判断表达式B
控制语句的出现可以让我们的程序具有逻辑性/条理性
控制语句包括几类?
3类:
选择语句 if、switch
循环语句 for、while、do while
转向语句 break、continue、return
[ 修饰符列表 ] 返回值类型 方法名(形式参数列表){
方法体;
return 返回值类型
};
static修饰
static修饰的统一都是静态的,都是类相关的,不需要new对象。直接采用“类名.”访问。
比如 CssName.xxxx 不需要Class sc = new Class(); sc.xxx
有默认值0,只执行一次,运行一开始就开辟了内存,内存放在全局
Java三大变量
局部变量(栈中、方法执行完成弹栈就无法使用)、
成员变量(堆中、被包含在实例对象中)、
静态变量(方法区中、随着类加载器加载的字节码文件一起放在方法区)
静态代码块
在类加载器加载的时候执行、只执行一次、作用全局
{
}
1)在同一个类中
2)方法名相同
3)形参不同(顺序、个数、类型)
————方法重载和返回值和修饰符无关—————
(同一个类、同一个方法名称、相同的形参、不同的返回值----> 不属于方法重载、是重写发生报错)
建议使用在:方法功能相似的方法上使用重载机制
本质上是方法自调
public void do(){
do()
};
public void main(){
do()
}
如果没有结束条件,JVM中的栈内存就会一值的压栈,最终导致内存溢出
示例-
public class OverLoadTest {
public static int sum(int n){
if (n == 0){
return 0;
}else{
return n + sum(--n);
}
}
public static void main(String[] args) {
int sum= sum(3);
System.out.println(sum);
}
}
面向过程
:分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象
把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
例如五子棋,
面向过程的设计思路就是首先分析问题的步骤:
1、开始游戏,2、黑子先走,3、绘制画面,
4、判断输赢,5、轮到白子,6、绘制画面,
7、判断输赢,8、返回步骤2,
9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。
而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为:
1、黑白双方,这两方的行为是一模一样的,
2、棋盘系统,负责绘制画面,
3、规则系统,负责判定诸如犯规、输赢等。
来源:知乎
术语:
OOA——Object-Oriented Analysis (面向对象分析方法)
OOD——Oeject-oriented design (面向对象设计)
OOP——Object-orented programing (面向对象编程)
实现一个软件的过程:
分析(A) --> 设计(D) --> 编程§
比如
public class test{
public static void main(){
Student s1 = new Student();
s1 = null;
System.out.println(s1.toString());
}
}
这段代码的如何去解释?
首先通过编译生成字节码文件,然后通过类加载器加载到 JVM的方法区中。
这时候方法区中包含 test.class
和 被标识static的main方法。
main方法执行,在栈内存中进行压栈,分配内存空间、然后到 Student s1 = new Student();
然后等式右边先开始 new Student();表示在堆内存中存放着一个student的实例(包含成员变量),这个实例有一个内存地址比如(0x123;
再到等式左边 Student s1 这个局部变量 s1存放在栈中给main方法分配的内存空间中,s1和student是引用关系,
所以s1中存放着student的内存地址,可以通过s1找到实例的对象
s1 = null 则是将 s1中存放的内存地址(0x123)改变为(null)
然后到System.out.println(s1.toString());
通过s1去使用toString()
方法。
因为s1没有student的内存地址,所以找不到s1,抛出异常,main方法出栈,程序结束。
[修饰符] 类名称(形参) {方法体}
没有返回值,方法名称和所在类的类名称相同。可以存在多个构造方法(重载)
思考:实例变量没有手动赋值的时候,实际上系统会默认赋值,
那么这个默认赋值操作是在什么时间进行的?
是在类加载的时候给这些实例变量赋值吗?不是,实例变量是在构造方法执行的过程中完成初始化的,完成赋值的。
封装有什么用?
一个类体当中的数据,假设封装之后,对于代码的调用人员来说,
不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问了。
另外,类体中安全级别较高的数据封装起来,外部人员不能随意访问,
来保证数据的安全性。
怎么进行封装,代码怎么实现?
第一步:属性私有化(使用private关键字进行修饰。)
第二步:对外提供简单的操作入口。get、set
继承的相关特性
① B类继承A类,则称A类为超类(superclass)、父类、基类,
B类则称为子类(subclass)、派生类、扩展类。
class A{}
class B extends A{}
② java 中的继承只支持单继承,不支持多继承,
③ 虽然 java 中不支持多继承,但有的时候会产生间接继承的效果,
例如:class C extends B,class B extends A,也就是说,C 直接继承 B,
其实 C 还间接继承 A。
④ java 中规定,子类继承父类,除构造方法不能继承之外,剩下都可以继承。
但是私有的属性无法在子类中直接访问。(父类中private修饰的不能在子类中
直接访问。可以通过间接的手段来访问。)
⑤ java 中的类没有显示的继承任何类,则默认继承 Object类,Object类是
java 语言提供的根类,也就是说,一个对象与生俱来就有Object类型中所有的特征。
⑥ 继承也存在一些缺点,例如:CreditAccount 类继承 Account 类会导致它们之间的耦合度非常高,Account 类发生改变之后会马上影响到 CreditAccount 类
能继承到什么?
除构造方法都可以继承、但private属性不可访问、拥有不可访问。
覆盖父类方法
什么时候考虑使用方法覆盖?
父类中的方法无法满足子类的业务需求,子类有必要对继承过来的方法进行覆盖。
什么条件满足的时候构成方法覆盖?
第一:有继承关系的两个类
第二:具有相同方法名、返回值类型、形式参数列表
第三:访问权限不能更低。
第四:抛出异常不能更多。
私有方法不能覆盖。
静态方法不谈覆盖。
多态基础语法
向上转型和向下转型的概念
向上转型也称为自动转形
Object testEntity = new TestEntity();
Object testEntity父类的引用可以指向子类的对象new TestEntity();
向下转型也称为强制转型
TestEntity o = (TestEntity)new Object();
那些条件需要用到强制转型?
需要调用或者执行子类对象中特有的方法
this在JVM里面是存放在堆中、被包含在实例对象中、this是一个引用 this 、引用的地址指向自己(指向被包含的类)
1.1、this是一个关键字,是一个引用,保存内存地址指向自身。
1.2、this可以使用在实例方法中,也可以使用在构造方法中。
1.3、this出现在实例方法中其实代表的是当前对象。
1.4、this不能使用在静态方法中。
1.5、this. 大部分情况下可以省略,但是用来区分局部变量和实例变量的时候不能省略。
1.6、this() 这种语法只能出现在构造方法第一行,表示当前构造方法调用本类其他的构造方法,目的是代码复用。
super能出现在实例方法和构造方法中。
super() 只能出现在子类的构造方法的第一行,通过当前的构造方法去调用“父类”中
的构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
TestMain(){
super();
}
TestMain(){
}
这两个方法是等同的,那么就说明所有继承关系中,子类的构建方法都含有父类的无参构造方法那么在JVM中堆中的实例对象中,这个实例对象的所包含的是所有父类和自己本身的成员变量和方法。
super. 可以省略,但子类中的成员变量和成员方法和父类相同时要使用用于区分。
super 不能使用在静态方法中。
super的使用:
super.属性名 【访问父类的属性】
super.方法名(实参) 【访问父类的方法】
super(实参) 【调用父类的构造方法】
———————————————————————————————
———————————————————————————————
最后一次更新 ——2020年5月16日
来源老杜Java零基础