文章目录
1、理解类型转换
1.1 int 和 long/double 相互赋值
int a = 10;
long b = 20;
a = b; // 编译出错, 提示可能会损失精度.
b = a; // 编译通过.
int a = 10;
double b = 1.0;
a = b; // 编译出错, 提示可能会损失精度.
b = a; // 编译通过.
long 表示的范围更大, 可以将 int 赋值给 long, 但是不能将 long 赋值给 int.
double 表示的范围更大, 可以将 int 赋值给 double, 但是不能将 double 赋值给 int.
1.2 int 和 boolean 相互赋值
int a = 10;
boolean b = true;
b = a; // 编译出错, 提示不兼容的类型
a = b; // 编译出错, 提示不兼容的类型
int 和 boolean 是毫不相干的两种类型, 不能相互赋值.
1.3 int字面值常量 给 byte 赋值
byte a = 100; // 编译通过
byte b = 256; // 编译报错, 提示 从int转换到byte可能会有损失
注意: byte 表示的数据范围是 -128 -> +127, 256 已经超过范围, 而 100 还在范围之内.
结论: 使用字面值常量赋值的时候, Java 会自动进行一些检查校验, 判定赋值是否合理.
1.4 使用强制类型转换
int a = 0;
double b = 10.5;
a = (int)b;
int a = 10;
boolean b = false;
b = (boolean)a; // 编译出错, 提示不兼容的类型.
结论: 使用 (类型) 的方式可以将 double 类型强制转成 int. 但是
- 强制类型转换可能会导致精度丢失. 如刚才的例子中, 赋值之后, 10.5 就变成 10 了, 小数点后面的部分被忽略.
- 强制类型转换不是一定能成功, 互不相干的类型之间无法强转.
1.5 类型转换小结
- 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型.
- 如果需要把范围大的类型赋值给范围小的, 需要强制类型转换, 但是可能精度丢失.
- 将一个字面值常量进行赋值的时候, Java 会自动针对数字范围进行检查.
2、移位运算
移位运算符有三个:
<< >> >>>
都是按照二进制位来运算.
左移 <<: 最左侧位不要了, 最右侧补 0.
右移 >>: 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)
无符号右移 >>>: 最右侧位不要了, 最左侧补 0.
3、Java关键字
4、逻辑控制
switch语句
基本语法
switch(整数|枚举|字符|字符串){
case 内容1 : {
内容满足时执行语句;
[break;]
}
case 内容2 : {
内容满足时执行语句;
[break;]
}
...
default:{
内容都不满足时执行语句;
[break;]
}
}
注意事项
注意事项1 break 不要遗漏, 否则会失去 “多分支选择” 的效果
注意事项2 switch 中的值只能是 整数|枚举|字符|字符串
注意事项3 switch 不能表达复杂的条件
5、格式化转换表
6、Java随机数
生成5个100以内的随机整数
Random random = new Random();
for (int i = 0; i < 5; i++) {
System.out.println(random.nextInt(100));
}
还有一种实现方法,但是这生成出来的都是double类型的
for (int i = 0; i < 5; i++) {
System.out.println(Math.random()*10);
}
7、方法的重载
有些时候我们需要用一个函数同时兼容多种参数的情况, 我们就可以使用到方法重载.
代码示例:
class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret = add(a, b);
System.out.println("ret = " + ret);
double a2 = 10.5;
double b2 = 20.5;
double ret2 = add(a2, b2);
System.out.println("ret2 = " + ret2);
double a3 = 10.5;
double b3 = 10.5;
double c3 = 20.5;
double ret3 = add(a3, b3, c3);
System.out.println("ret3 = " + ret3);
}
public static int add(int x, int y) {
return x + y;
}
public static double add(double x, double y) {
return x + y;
}
public static double add(double x, double y, double z) {
return x + y + z;
}
}
方法的名字都叫 add。但是有的 add 是计算 int 相加,有的是 double 相加;有的计算两个数字相加,,有的是计算三个数字相加。同一个方法名字,提供不同版本的实现,称为 方法重载。
重载的规则
针对同一个类:
方法名相同
方法的参数不同(参数个数或者参数类型)
方法的返回值类型不影响重载.
8、JVM内存划分
程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址.
虚拟机栈(JVM Stack): 重点是存储局部变量表(当然也有其他信息). 创建的 int[] arr 这样的存储地址的引用就是在这里保存.
本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量.
堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如 new int[]{1, 2,3} )
方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据.方法编译出的的字节码就是保存在这个区域.
运行时常量池(Runtime Constant Pool): 是方法区的一部分, 存放字面量(字符串常量)与符号引用. (注意 从 JDK1.7 开始, 运行时常量池在堆上).
总结:
局部变量和引用保存在栈上, new 出的对象保存在堆上.
堆的空间非常大, 栈的空间比较小.
堆是整个 JVM 共享一个, 而栈每个线程具有一份(一个 Java 程序中可能存在多个栈).
9、类和对象
面向过程: 打开冰箱 → 放入牛奶 → 关闭冰箱
面向对象: 打开冰箱,存储,关闭冰箱都是操作冰箱的行为。冰箱就是一个对象,只要操作冰箱所对应的功能,都要定义在冰箱中。
【面向对象概念】:
1.面向对象是思考问题的一种思考方式,是一种思想。比如:概念与实例。理论与实践。名和实等等。
2.类就是一类对象的统称。对象就是这一类具体化的一个实例。
3.面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。
【面向对象设计】:
面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法!(被动的一方是数据的拥有者,主动的一方是执行者)
10、封装
我们写代码的时候经常会涉及两种角色: 类的实现者和类的调用者.
封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度.
10.1 private实现封装
private/ public 这两个关键字表示 “访问权限控制” .
- 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
- 被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用.
10.2 getter和setter方法
当我们使用 private 来修饰字段的时候, 就无法直接使用这个字段了.
代码示例:
class Person {
private String name;//实例成员变量
private int age;
public void setName(String name){
//name = name;//不能这样写
this.name = name;//this引用,表示调用该方法的对象
}
public String getName(){
return name;
}
public void show(){
System.out.println("name: "+name+" age: "+age);
}
}
public static void main(String[] args) {
Person person = new Person();
person.setName("caocao");
String name = person.getName();
System.out.println(name);
person.show();
}
- getName 即为 getter 方法, 表示获取这个成员的值.
- setName 即为 setter 方法, 表示设置这个成员的值.
- 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例
的引用. - 不是所有的字段都一定要提供 setter / getter 方法, 而是要根据实际情况决定提供哪种方法.
11、构造方法
11.1 基本语法
构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作.
new 执行过程
- 为对象分配内存空间
- 调用对象的构造方法
语法规则
- 方法名称必须与类名称相同
- 构造方法没有返回值类型声明
- 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
注意事项
- 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
- 若类中定义了构造方法,则默认的无参构造将不再生成.
- 构造方法支持重载. 规则和普通方法的重载一致.
11.2 this关键字
this表示当前对象引用(注意不是当前对象). 可以借助 this 来访问对象的字段和方法.
class Person {
private String name;//实例成员变量
private int age;
private String sex;
//默认构造函数 构造对象
public Person() {
//this调用构造函数
this("zh", 21, "man");//必须放在第一行进行显示
}
//这两个构造函数之间的关系为重载。
public Person(String name,int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
public void show() {
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main{
public static void main(String[] args) {
Person person = new Person();//调用不带参数的构造函数
person.show();
}
}
12、代码块
12.1 什么是代码块
使用{} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块
- 静态块
- 同步代码块
12.2 普通代码块
定义在方法中的代码块.
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
12.3 构造代码块
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
class Person{
private String name;//实例成员变量
private int age;
private String sex;
public Person() {
System.out.println("I am Person init()!");
}
//实例代码块
{
this.name = "zh";
this.age = 21;
this.sex = "man";
System.out.println("I am instance init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
12.4 静态代码块
使用static定义的代码块。一般用于初始化静态成员属性。
class Person{
private String name;//实例成员变量
private int age;
private String sex;
private static int count = 0;//静态成员变量 由类共享数据 方法区
public Person(){
System.out.println("I am Person init()!");
}
//实例代码块
{
this.name = "zh";
this.age = 21;
this.sex = "man";
System.out.println("I am instance init()!");
}
//静态代码块
static {
count = 10;//只能访问静态数据成员
System.out.println("I am static init()!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
System.out.println("===");
Person p2 = new Person();//静态代码块是否还会被执行?
}
}
执行结果:
I am static init()!
I am instance init()!
I am Person init()!
===
I am instance init()!
I am Person init()!
- 静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
- 静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。
13、toString方法
- toString 方法会在 println 的时候被自动调用.
- 将对象转成字符串这样的操作我们称为 序列化.
- toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法实现我们自己版本的转换字符串方法.
- @Override 在 Java 中称为 “注解”, 此处的 @Override 表示下面实现的 toString 方法是重写了父类的方法.
14、匿名对象
匿名只是表示没有名字的对象.
- 没有引用的对象称为匿名对象.
- 匿名对象只能在创建对象时使用.
- 如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象.