Skip to main content
 首页 » 编程设计

Java基础知识总结

2022年07月19日30落叶无声

1.java中没有C++中的引用,change_value(int& p);在java中是编译不过的。

2.Android驱动 = Linux驱动 + 封装

3.Android系统的层次结构
Java <--> App
----------
FrameWork 难点
----------
封装 非常简单
----------
驱动 就是Linux的驱动

4.Android中检测耳机的机制和Linux的不同。有时候相机用不了,蓝牙用不了,这时候不仅仅需要查驱动,还要查整个框架。

5.推荐Java开发书籍: 《Java开发实战经典》李兴华
若自己安装Ubuntu,参考:韦东山第4期_Android驱动深度开发\韦东山Android系统视频使用手册20160303.pdf
硬盘至少预留80G
a.root分区:20G, 从中划出6G用作swap
b.work分区:60G,
c.内存4G

6.安装Java开发环境
sudo apt-get update
sudo apt-get install openjdk-7-jdk
sudo apt-get install openjdk-7-jre

注释:
1、apt-get update是同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包。
2、apt-get update只是更新了apt的资源列表,没有真正的对系统执行更新。如果需要,要使用apt-get upgrade来更新。

7.C和Java类比
(1) C中是从main()开始执行,Java中也是一样的,只不过main的书写方式不同。
(2) C中需要包含头文件,Java中不需要。
(3) Java中无指针。
(4) C中malloc()分配的内存在程序退出后系统会自动帮你free(),若程序一直运行不退出,需要自己free();java中有new但是没有释放操作,
系统会帮助我们自动释放。eg: int p[] = new int[10]; p = null; 用来释放堆空间中的int[10]。java中的垃圾回收机制在没有引用的时候自动回收掉。也就是使用new来分配,不需要我们手动释放,把变量设置为null即可。
(5) java中数据类型转换比C中严格,eg: float pai = 3.14; 编译报错,3.14默认是double类型,不能自动转换成float类型。
(6) java中的运算符、表达式、语句 都和C中的完全一样。
(7) C语言中的函数成为函数,java中的函数称为方法。
(8) 在C中使用‘,’来分割打印的内容,在java中使用‘+’来分割,eg:system.out.println("before function2"+p[0]);

8.java中的数据类型转换
自动转换:能转换的前提是数据不丢失,注意整数默认是int, 小数默认是double

强制转换:暂无内容

错误:
  float f = 3.14;
修正:
  float f = (float)3.14; 使用强制类型转换 或 float f = 3.14f; 后面带个f表示是float类型

  short a = 4; 正确的,对于整数编译器会帮我们判断其范围,若是没有超过short的值域就是可以的。
  short a = 40000; short属于-32768--32767, 40000超过了short的表示范围,不能自动转换,报错。

  int i;
  short s;
  s = i; 这个肯定报错的,编译期不知道i的值是什么的。
  s = s + 1; 这个也会出错,因为加1可能溢出。或者说中间结果是int类型,编译时又不知道其值,所以不能转换成short类型。对于short byte类型的变量在运算的时候为了保证精度,中间结果都保存为int类型。修正:s = (short)(s + 1);
  s = s + s; 也会错误,因为为了保证精度,中间结果也是int类型,实际是先各自转换成int类型后再相加。


9.编译Java程序
  $ javac Hello.java
  $ ls
  Hello.class Hello.java 编译生成Hello.class可执行程序!!
  $ java Hello 启动java虚拟机,在这个虚拟机里面运行这个程序
  Hello world! 打印出Hello world!
  $

Hello.java 这个文件名中首字母大写的原因:Java的编程规范中类的名字的首字母要大写,而文件的名字要与类名保持一致。

TODO:翻译man javac, man java

10. Java的数据类型
基本数据类型:比C多了boolean和byte两个基础数据类型(多出byte的原因可能是Java使用unicode编码,char是2字节)

引用数据类型:数组、类、接口、null
(1) java中的所有数组永远都是引用数据类型,其元素都是放在堆空间的,即使是静态分配int p2[] = {1, 2, 3} p2存放在栈中,{1,2, 3}在堆中。
(2) 除了基本的数据类型之外所有的数据类型都是引用数据类型。

(3) C中的char str[] = "abc"; 在java中是不行的,"abc"是一个类,换成String str[] = "abc";是可以的。str在栈中,a b c 存储在堆中


11.UltraEdit中 文件->转换 可以实现多种编码格式之间的转换

12.重载的实现只与参数有关而与返回值无关的原因:需要根据参数匹配选择一个重载的函数,是不知道返回值是什么类型的,也就无法根据返回值类型进行匹配。

13.C中函数传参func(int *p) 在java中变为 func(int p[]), p[]就相当于C中的指针。


测试下面是可以的
char str2[] = new char[10];
char str3[] = str2;

TODO:
1.C中malloc()分配的内存在程序退出后系统会自动帮你free(),若程序一直运行不退出,需要自己free() !!

14.Java中返回字符串之间可以直接使用‘+’号,因为“guangdong”和name都是String类对象,String类重装了‘+’
String getName() {
  return "guangdong "+name;
}

15.类比C:Java中的类就相当于一个类型,对象就相当于一个变量

16.在一个.java源文件中只能有一个public class, 存在的其它class不能写成public的

17.构造方法格式:函数签名中无返回类型
eg:
访问权限 类名称(参数) {
  程序语句
}

18.类中有个属性name,参数又是name,若直接使用name=name;根据就近原则,使用的都是参数name。加上this修饰成员属性的name。this表示当前类或当前对象
public Person (String name) {
  this.name = name;
}

补充:

构造函数中第一句语句可以使用this(args);来调用其它构造函数

public class Handler { 
    public int a; 
    public Handler(int a) { 
        this.a = 5 * a; 
    } 
    public Handler() { 
        this(10); 
    } 
 
    void printInfo(String head) { 
        System.out.println(head + ": a= " + a); 
    } 
 
    // void printInfo() { 
    //     this("This() Test"); //error: call to this must be first statement in constructor 
    // } 
 
    public static void main(String args[]) { 
        Handler h = new Handler(); 
        System.out.println("h.a= " + h.a); 
    } 
} 
 
/* 
$ java Handler  
h.a= 50 
*/

19.加static修饰的类成员属性或方法就不依赖与具体的对象就可以调用。static修饰的也可以直接在对象中调用。

20.代码块(构造块)
类似于构造函数,在创建一个对象的时候构造块会执行,而且是先执行构造块,再执行构造方法。在类中直接使用{}括起来的代码就称为构造块。
eg类的定义中直接:
{
  count++;
}

21.静态代码块
静态代码块最先执行,而且只执行一次,比如创建3个对象,只有在创建第一个对象的时候执行静态代码块,之后都不执行了。
执行顺序:先执行静态代码块(只一次),再执行代码块,再执行构造函数。
定义静态代码块:在类中直接加static{ }定义代码块
static {
  代码块
}

简介
在java中用{}括起来的称为代码块,代码块可分为以下四种:
(1)普通代码块:类中方法的方法体中使用{}起来的部分,注意这是成员方法中的,和普通代码没什么区别,按顺序执行。

(2)构造代码块:构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行。
直接在类中定义且没有加static关键字的代码块称为{}构造代码块。构造代码块在创建对象时被调用,每次创建对象都会被调用,并且构造代码块的执行次序优先于类构造函数。如果存在多个构造代码块,执行顺序由他们在代码中出现的次序决定,先出现先执行。

(3)静态代码块:用static{}包裹起来的代码片段,只会执行一次。静态代码块优先于构造块执行。
在java中使用static关键字声明的代码块。静态块用于初始化类,为类的属性初始化。每个静态代码块只会执行一次。由于JVM在加载类时会执行静态代码块,所以静态代码块先于主方法执行。

(4)同步代码块:使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性。同步代码块需要写在方法中。

注意:
a. 静态代码块不能存在于任何方法体内(包括public static main()中)
b. 静态代码块不能直接访问实例变量和实例方法,需要通过类的实例对象来访问

静态代码块和构造代码块的异同点:
相同点:都是JVM加载类后且在构造函数执行之前执行,在类中可定义多个,一般在代码块中对一些static变量进行赋值。
不同点:静态代码块在非静态代码块之前执行。静态代码块只在第一次new时执行一次,之后不在执行。而非静态代码块每new一次就执行一次。

方法体中定义的局部变量在代码块中可见,重复定义编译报错。

public class Test { 
    public static String STATIC_FIELD = "静态属性: "; 
    // 静态块  
    static { 
        System.out.print(STATIC_FIELD); 
        System.out.println("静态代码块1"); 
    } 
    public String field = "非静态属性: "; 
    // 非静态块  
    { 
        System.out.print(field); 
        System.out.println("非静态代码块1"); 
    } 
    public Test() { 
        System.out.println("无参构造函数"); 
    } 
    public static void main(String[] args) { 
        Test test1 = new Test(); 
        System.out.println("--------1--------"); 
        { 
            System.out.println("普通代码块1"); 
        } 
        Test test2 = new Test(); 
        System.out.println("--------2--------"); 
        { 
            System.out.println("普通代码块2"); 
        } 
    } 
    // 非静态块  
    { 
        System.out.print(field); 
        System.out.println("非静态代码块2"); 
    } 
    // 静态块  
    static { 
        System.out.print(STATIC_FIELD); 
        System.out.println("静态代码块2"); 
    } 
} 
/* 
[ubuntu @java_test]$ java Test  
静态属性: 静态代码块1 
静态属性: 静态代码块2 
非静态属性: 非静态代码块1 
非静态属性: 非静态代码块2 
无参构造函数 
--------1-------- 
普通代码块1 
非静态属性: 非静态代码块1 
非静态属性: 非静态代码块2 
无参构造函数 
--------2-------- 
普通代码块2 
 
*/

22.类的{}后面可以加也可以不加‘;’

还有一种不加{ }的代码块,直接在类中(非类的成员函数中)定义变量并初始化,eg: List<Noder> nodeList = new ArrayList<Noder>(); 其中nodeList并不是静态成员变量!

23.静态成员函数中不能引用非静态成员变量也不能调用非静态成员方法,因为不知道非静态成员变量是哪个类的,且不知道其是否存在。

24.面向对象程序设计三大特性:
①封装性:把属性和方法封装成一个整体,并加以访问权限控制。
②继承性:目的主要是复用代码
③多态性:方法的重载与复写

25.java中没有加任何权限修饰测成员变量的属性是default的,本包内可以访问,和C++的不一样,C++中成员属性默认是private的。

26.如果我们直接使用System.out.println()输出对象,那么System.out.println()会自动去调用这个对象的toString()方法(继承Object类的)获取它的返回值(包名类名@Hash值),然后输出。当然也可以重写这个方法。

27.java的类中可以直接定义并初始化成员变量,eg: int[] a = new int[5]; List<Person>=new ArrayList<Person>();,这些定义并初始化的变量只是类的普通成员变量,和在构造函数中初始化的基本上没有什么区别。

28.java比C和C++慢的原因

java程序从源文件创建到程序运行要经过两大步骤:
(1).源文件由编译器编译成字节码(ByteCode)
(2).字节码由java虚拟机解释运行。因为java程序既要编译同时也要经过JVM的解释运行,所以说Java被称为半解释语言( "semi-interpreted" language)。

java(*.class)-> JVM -> 机器码
由于需要JVM做中介java程序比C++运行效率低。一个操作系统下编译的*.class可以运行在其它的操作系统下,(当然要装不同操作系统下的
JVM)。这是所谓的(compile once, run anywhere). C++比C慢, 可能慢10%,不像java和C的差别那么大。

java具体慢在哪里:
(1).解释性语言固有开销:java程序在运行时类加载器从类路经中加载相关的类,然后java虚拟机读取该类文件的字节,执行相应操作.而C编译的时候将程序编译成本地机器码.一般来说java程序执行速度要比C 慢10-30倍.即使采用just-in-time compiling (读取类字节码文件字节后,编译成本地机器码)技术,速度也要比C 慢好多.
(2).字节码加载执行开销:java程序要加载类字节,然后执行,这也是导致java运行速度慢的原因.
(3).运行时溢出检测开销:在程序运行过程中,java虚拟机要检测数组是否越界,在C 中则不检测.
(4).堆与栈的区别:java中所有的对象都创建在堆中,没有对象被创建在stack中,而C 有的对象和变量是创建在stack中的
(5).运行时引用检测开销:java在运行过程中检测对象的引用是否为空,如果引用指向都空指针,且执行某个方法时会抛出空指针异常
(6).运行时类型检测开销:java运行时对类型检测,如果类型不正确会抛出ClassCastException异常.
(7).GC巨大开销:java的垃圾回收机制较C 由程序员管理内存效率更低.
(8).类型转换开销:java中的原始数据类型在每个操作系统平台长度都是相同,而C 这些数据类型长度是随操作系统的不同而不同,所以java在不同操作系统上执行时有个转化过程.
(9).String类型开销:在java中String 是UNICODE.当java要操作一个 ASCII string 时,比C 效率上相对要低一些.
(10).动态链接开销:java中采用的是动态链接(C也是动态链接的)

综上所述,C 语言的运行效率 要比 Java 的高很多(有人说是高10-30倍)。因为 C 语言是属于编译型的,而 Java 语言则是半解释型的。Java 语言运行时要先被翻译成计算机能 辨识的二进制代码,然后才能执行。

29. java类运行的过程

(1).类的加载
(2).类的执行
JVM主要在程序第一次主动使用类的时候,才会去加载该类。也就是说,JVM并不是在一开始就把一个程序就所有的类都加载到内存中,而是到不得不用的时候才把它加载进来,而且只加载一次。

public class Main { 
    public static void main(String[] args) { 
        Animal animal = new Animal("Dog"); 
        animal.printName(); 
    } 
} 
 
class Animal { 
    public String name; 
    public Animal(String name) { 
        this.name = name; 
    } 
    public void printName() {  
        System.out.println("Animal [" + name + "]"); 
    } 
}

(1).在编译后得到Main.class后, $ java Main 会启动一个jvm进程,jvm进程从classpath路径中找到一个名为Main.class的二进制文件,将Main类的信息加载到运行时数据区的方法区内,这个过程叫做Main类的加载。
(2).然后JVM找到Main的主函数入口,开始执行main函数。
(3).main函数的第一条命令是Animal animal = new Animal("Dog");就是让JVM创建一个Animal对象,但是这时候方法区中没有Animal类的信息,
所以JVM马上加载Animal类,把Animal类的类型信息放到方法区中。
(4).加载完Animal类之后,Java虚拟机做的第一件事情就是在堆区中为一个新的Animal实例分配内存, 然后调用构造函数初始化Animal实例,
这个Animal实例持有着指向方法区的Animal类的类型信息(其中包含有方法表,java动态绑定的底层实现)的引用。
(5).当使用animal.printName()的时候,JVM根据animal引用找到Animal对象,然后根据Animal对象持有的引用定位到方法区中Animal类的类型信息的方法表,获得printName()函数的字节码的地址。开始运行printName()函数。

30.反编译java的字节码文件

$ javac XXX.java
$ javap -v -c XXX  // -v打印出详细信息

31.若定义了与系统同名的类会覆盖掉系统的类,如下自己定义了一个System类后导致如下报错:

error: cannot find symbol
  System.out.println("Falsh shutDown");

32.-verbose选项

$ javac -verbose StaticMethodCall.java  加-verbose可以看出搜索库路径、编译时加载了那些class文件。
$ java -verbose StaticMethodCall  可以看出启动java虚拟机的时候加载和巨多.jar文件。

$ java -verbose:jni StaticMethodCal 可以看出JNI库加载的信息


本文参考链接:https://www.cnblogs.com/hellokitty2/p/10425684.html