java语法基础 - 第二部分

运算符
原码、反码、补码 —— 假设机器字长8位

解决计算机花大功夫确定符号位问题 → 让 符号位 参与 运算 (补码、反码符号位都可参与运算)
计算机运算只进行 加法 运算

  1. 最高位存放 符号位0代表正、1代表负

0000 0001 → 机器数、+000 0001 真值

  • 原码:
    8位二进制数实际值范围:[-127, +127]

  • 反码:解决加法运算、符号位参与运算
    • 不足: 并未解决 +0、-0两个都表示0的细节
    • 正数反码是本身,负数的反码:符号位不变,其余位取反
+1:原码:0000 0001     反码:0000 0001
-1:原码:1000 0001     反码:1111 1110


+0:原码:0000 0000     反码:0000 0000

// 导致有两个反码表示0   0000 0000( +0 )、1111 1111( -0 ) 
反码进行运算:+0 + +0 = 0000 0000 ( +0 )
反码进行运算:+1 + ( -1 )  = 0000 0001  + 1111 1110 = 1111 1111 → 原码:1000 000 ( -0 )

  • 补码:在补码的基础上,解决双0问题、且其中一个0能多表示一个负数
    • 正数补码是本身,负数的补码:符号位不变,其余位取反,再加1( 即反码的基础上加1 )
+1:原码:0000 0001     补码:0000 0001 
-1:原码:1000 0001     补码:1111 1111
-127:原码:1111 1111      补码:1000 0001

+1 + ( -1 ) = 0000 0001 + 1111 1111 = 0000 0000 → 原码:0000 0000
-1 - ( -127 ) = 1111 1111 + 1000 0001 =  1000 0000 → 无原码,补码1000 0000 即表示-128
各种运算符
  • ==: 判断两对象内存地址是否相等
  • instanceof: 判断左边的对象是否是右边类的实例

由这个语句从中也可以得知:基本变量不是对象实例,基本变量的数组是对象实例

String a = "Hello";      //直接赋值字符串,静态绑定,编译器已经确定好放置在常量池 - 常量池的变量 ==  比较的是值
String b = new String("Hello"); // 动态绑定,运行期确定地址
if (b instanceof String) {
    System.out.println("equal");
}

移位: 计算机中一个数的位数是固定

例如 → 整数:4字节、32位
符号位永远是左边的第一个

  • <<: 补码整体左移动,右边补0
  • >>: 补码整体右移动,左边补符号位
  • >>>(无符号移动): 补码整体右移动,左边补0
int a = -5;
println(Integer.toBinaryString(a) ) // 输出a的补码     
int b = a<<1     //十进制结果 -10
int c = a>>1     //十进制结果  -3;

//因为左边补0,导致补码成为正数
int d = a>>>1  //十进制结 2147483645


二进制位与运算符:&

即把字符转换成二进制,对应位的二进制数进行 与运行

int a = 1;              // 二进制数:001
int b = 5;              // 二进制数:101
println( a & b )   // 二进制与运算: 001  输出:十进制1
控制执行语句

foreach :for 组成而来的:for( x : 数组)
 
 
跳转的程序控制

  1. continue:跳出当前的迭代
  2. break : 跳出循环

goto中的标签跳(label: + 直接迭代(循环)语句)

  1. continue label : 跳转到llabel位置,再次进入迭代
  2. break label: 跳转到label位置,并且不再进入 label : 紧随的迭代(循环)

 
switch语句:多路选择,不过选择因子必须是 int 或者 char

一旦匹配到”对应的因子“,如果没有break; 会接着执行后面的选择因子语句

 

调用

重载 :
①如果重载的数据类型小于或者大于,数据类型会被提升或者窄化。
②只要方法名同有无返回值(int 、 void)并无影响。

方法的调用

  • 对象.方法名( 参数 )→ 类名.方法名( 对象名{引用、位置},参数 )
     
  • 方法调用时参数的类型判断是发生在编译前的,故泛型要检验时要放在形参上,而不是在方法内部进行转换(实质一点都没有转换,运行时已经抹除泛型)

   这是编译器调用方法时的隐形操作。

Class Father<T> {
    List<T> list = new ArrayList<T>();
    public void add(T a) {   //在编写调用方法时,会检验类型
        list.add(a);    //一旦调用成功必定是 初始化时的 T类型
    )
 }
    
 注意   public void add(Object a) {
        list.add(  (T)a )  //写的是强制转换,实质并没有强制转换,因为代码在运行时,有关T的信息完全被抹除
        }

 
this关键字 : 方法内使用,表明这是当前调用方法的对象

   构造函数(构造器)可以调用其他重载了的构造器函数→新对象的初始化。 不过只能调用一个

 
static成员函数:不能调用非静态的成员方法。因为静态方法可以只用类名调用,而 非静态的方法一定要有指定类型的对象调用才能。

 
当对象的引用 = null    System.out.println(引用) 依然会调用对象的toString方法进行转换。

 
方法调用的参数栈: 当调用语句时将参数、返回地址入栈;当遇到函数结束时退栈返回

public class Test {
     public static void p(int n) {
           if(n>1 && n%2==1) {
                p(n-1);
           }
           System.out.println(n);    
           if (n>1 && n%2==0)
                p(n-1);
     }
     public static void main(String[] args) {
           Test.p(5);   //参数入栈顺序 p(5) → p(4) → p(3) → p(2) → p(1)
                         // 出栈顺序:入栈顺序的反方向,先进后出
                         //输出:4 2 1 3 5
     }
}
native关键字
  • 不是java原生的方法,用其他语言实现的函数
  • JNI( java native Interface ): 可以允许 本地调用 其他语言编写的方法,类库( 打包成DLL使用
  • 只有该关键字修饰的方法 被调用,相关被调用的DLL实现才会被载入内存
垃圾回收(清理)

垃圾回收器:只会释放new创建的(无任何引用)对象,如果由非new的内存只能由 终结函数finalize() 手动释放。

垃圾回收模式:

  • 引用计数: 引用接近对象时+1,引用为null或者离开作用域时-1.计数为0就释放对象。缺点:循环引用,导致内存泄露
  • 自适应: ①停止-复制(用于碎片多)②标记清理(用于垃圾少)③分代(块的引用次数、感觉类似标记)

 
finalize() : 调用它后,只能等到 下一次垃圾回收时刻 才释放内存,如果垃圾回收一直无动作,则该准备终结的内存一直不会释放。可根据对象情况自己重载系统的finalize();

class book {
     boolean checkout = true;
     protected void finalize() {
           if(checkout) {
                System.out.print("你还有书未登记");
           }
           else 
                System.out.println("你的书已经全部登记");
    }
}
public class lx {
     public static void main(String[] args) {
           new book(true);      //无引用的对象 垃圾回收一定会认为后面用不到,从而准备回收
           System.gc();           //强制的执行 (new无引用的对象) 终结工作( finalize) ,垃圾回收器也会开启。    
     }
}
初始化
  • 数组进行初始化时有 三种方式
Integer[] a = new Integer[2];
Integer[] a = new Integer[] { 元素 };
Integer[] a = { 元素 }}
  • 子类进行初始化父类的构造器需要用到 super() —— 只能出现在子类构造器中的第一行
     
  • 常量final类型的变量名按照惯例大写、下划线
     
  • 调用时方法的参数必须是初始化(即有 " 值 ")
     
  • 实例化对象时,类内部执行顺序:1.一定会初始化静态变量 2.类内无名执行字段 3.有对象初始化(基本变量初始化(一定会)、其他如类内变量对象需手动初始化,系统不会帮你赋值 → 构造函数)(继承的对象则先父类后子类)

静态代码块、字段 在一个类有且只能执行一次

  • 形参:Object… args 等价于 Object[] args
     
  • 如果java中有多个在不同包名的同名类,无定义包名初始化的对象优先用当前包的类 → java系统类   如果初始化有包名限制则优先用有包名规定的类来初始化 或者 导入import所用类

前者调用时的参数可以不像后者那样初始化一个数组,可写成一个一个的对象

static void print1 (Object[] args) {
    for (Object item : args) {
        System.out.println(item);
    }
}
static void print2 (Object... args) {
    for(Object item : args) {
        System.out.println(item);
    }
 }
 print1( new Int[] {1,2,3,4} );
 print2(1,2,3,4)                        //这两条调用是等价的,peinr2的参数系统会自动的转为数组

类的初始化:

  1. 类定义字段的时候初始化(对类内的对象字段以及数组不会初始化
  2. 类的构造器中
  3. 将要使用时进行初始化(不再构造器中初始化),即 惰性初始化
深/浅拷贝
  • 浅复制: 类实例的属性 (元数据:值传递、类内对象:引用(地址传递)
  • 深复制: 类实例的属性 (元数据:值传递 类内对象:新的对象,而不是传引用)
class Subject {
    String subject;
    Subject(String subject) {
        this.subject = subject;
    }
}

class Student implements Cloneable{
    String name;
    int age;
    Subject sub;
    Student(String name, int age, String subject) {
        this.name = name;
        this.age = age;
        sub = new Subject(subject);
    }
    public Object clone() {     // 浅拷贝   
        try {
            return super.clone();
            //深拷贝
            //  Student a = new Student( name , age, sub.subject )
            // return a;     
            
        }catch(Exception e) {
            return null;
        }
    }
}

Student stu1 = new Student("lrc","10",  "数学");
Student stu2 = (Student)stu1.clone();
stu1.age = 10;                  //并无改变元数据 stu2 的值
stu1.sub.subject = "英语"   //因为是引用所以改变了 stu2.sub.subejct 的值,同一引用

复用类(组合、继承、代理)

组合 : 增加功能而不是暴露接口(车对象与轮子对象的关系),类内置组合对象一般为private (is - a)
继承 : 会把父类的所用方法继承到子类 (have - a)

继承表达行为间的变化,字段(类内对象(组合)、基本变量)表达状态上的变化
继承不能降低可视的成员函数的访问权限
类成员能够降低访问权限,实在是两个不同的变量,虽然他们变量名一样 —— 因为有 super能访问父级的类成员

class Father {
    int a = 10;
    public void cout() { }
}

class Son extends Father {
    private int a;          //降低了继承的类成员访问权限,不过实质是两个不同的变量。
    void cout() {}   // 出错,权限从 公有 → 包权限 故会报错
    public void cout() {
        System.out.prntln( a + " " + super.a );  // outpur:0 10
}

代理 : 某类引进需要代理的对象,在类中定义方法调用对象的成员函数

能自定义的引进代理对象的成员方法,而不像继承一样一股脑的继承所有祖先类的方法

class a {
    void up(int velocity) {}
    void down(int velocity){}
 }
public class b {
    private a daiLi = new a();          //屏蔽代理对象dalLi的细节
    void up() {    daiLi.up();     }         //类b代理a类的对象,自由的引进a类的方法,重新包装
    void down() {  daiLi.down();  }
 }  

 
调用

  • 父类的静态函数用 父类的类名调用
  • 父类的普通成员函数 用关键词 super 调用

 
方法签名: 方法名 + 形参列表

 
子类实例初始化顺序: 先祖先类 → 子类字段 → 子类构造函数

 
@override注解:帮检查重写父类方法的正确性,例如子类重载的方法名是否与父类同,以及返回类型等   可当关键词用

 
向上转型: 即子类对象转成父类的对象(注父类是子类的子集) - 意味着子类有的父类无的接口被屏蔽

向下转型一定要 强制转换,要不然提示错误。
注意:只有引用本身是子类的对象实例,才能向下转型
向上转型并不能调用父类的private(私有方法)—— 可用 @Override注解验证

public class amphibian {
    void eat() {
        System.out.println(" 我是两栖动物 ");
     }
     static void cout (amphibian a) {          //向上转型入口 
        a.eat();
     }
class public frog extends amphibian{
    @Override void eat() {
        System.out.println(" 我是青蛙(两栖动物)");
    }
    public static void main(String[] main) {
        frog f = new frog();
        f.eat();                        //输出:我是青蛙(两栖动物)
        amphibian.cout(f);        //输出:我是青蛙(两栖动物)证明向上转型如果调用的是父类与子类重写同名的方法,则还是会调用子类重写的方法。

 

final(不可更改)数据

变量即是 static 又是 final 则变量名 大写且下划线分隔

  1. 对于基本数据类型(不可改变值,需要定义时要初始化)
  2. 对于对象,只能保证引用(对象地址)不变,其对象里面的内容可以更改
  3. 允许空白域(即声明了一个final变量可不赋初始值,不过必须在构造器中初始化
  4. 可应用于在方法形参列表中,即不能改变变量的值,引用的值(地址)
  5. 锁定方法:即内嵌方法(复制方法代码到当前调用的位置-用方法代码的复制体)取代 转到方法地址(压栈,跳回原地址-用原方法代码),不过hotspot技术会优化内嵌代码

private方法隐含final,即不能重载、重写

  1. 锁定类( 定义类时修饰final ):即该类不能被继承
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值