欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java基础复习第一天

程序员文章站 2022-04-04 09:49:36
...

今日目标

Java概述部分: 可以参考菜鸟教程.

了解Java主要特性

java语言是简单的

java语言是面向对象的

java语言是高可移植的

java语言是安全的

java语言是多线程的

了解Java发展史

1995年java语言诞生

1996年第一个JDK1.0诞生

了解JDK目录

bin目录:包含一些开发java程序的工具包,有javac.exe(编译工具),java.exe(运行工具),jar.exe(打包工具)

include目录:包含一些C语言的头文件,用于支持java程序设计

jre目录:java运行时环境的根目录

jre/lib:包含开发java的核心类库文件

lib目录:包含开发java的类库文件

了解JDK环境配置

path:配置path变量,将安装好的jdk的bin目录的路径配置到path中,可以在任意文件夹都能使用java、javac命令运行。

classpath:作用是指定类搜索路径,要使用自己一些编写好的java类,得将jdk安装目录下的lib子目录下的dt.jar、tools.jar设置到classpath中

java_home:将自己安装好的jdk的bin目录路径配置进去,eclipse、tomcat就能通过搜索java_home里已经配置好的路径,找到并使用安装好的jdk

了解JVM、JDK和JRE

JVM:java虚拟机,是java能跨平台的主要原因,JVM有针对不同的操作系统的特定实现,目的是使用相同的字节码,它们会运行出相同的结果
JDK:java开发工具包,是整个java开发的核心,内含JRE、编译器、java类库、一推Java工具
JRE:java运行时环境,是运行基于java编写的程序所不可缺少的运行环境,内含JVM

了解Java程序执行流程

java程序必须结果编写、编译、运行三个步骤。
编写好一个.java文件,jvm将java文件编译成可执行的.class文件,在对编译好的.class文件进行执行。

Java基础语法部分

静态变量(类变量)

用static修饰的变量就称为静态变量。静态变量可以不用new对象就可以调用,直接用类名.静态变量就可以进行调用

静态变量在第一次被访问时创建,在程序结束时销毁	

static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法

局部变量

类的方法中的变量

局部变量是定义在方法、构造方法、语句块中的

局部变量是在方法,构造方法,语句块初始化后创建的,当它们执行完以后,变量就会被销毁

局部变量是在栈上分配的。

局部变量没有默认值,所以在声明完以后,必须在类、方法初始化后才可以被使用

实例变量

实例变量声明在类中,但在方法和构造方法外

实例变量在对象创建的时候创建,在对象销毁的时候被销毁

实例变量对类中方法、构造方法和语句块中可见的,所以一般情况下应该把实例变量设为私有

实例变量具有默认值。数值类型的默认值是0,boolean类型的默认值是null	

数据类型

基本数据类型

八大基本数据类型:int,short,long,byte,char,boolean,float,double

引用数据类型

对象类型和数组类型(在java中不是基本数据类型就是引用数据类型)

所有的引用类型默认值都是null

常量

常量在程序中是不能被修改的

变量传递(值传递、引用传递)

在java中,数据类型分为两种:基本数据类型、引用数据类型

基本类型保存的是值,所以变量就是数据本身

引用类型保存的是引用值,所谓引用值就是对象在内存中的“首地址”,通过对这个引用值来操作对象

拆箱装箱

自动装箱:java自动将原始类型转为引用类型的过程,自动装箱时编译器会调用valueOf()方法,将原始类型转为对象类型

自动拆箱:java自动将引用类型转化为原始类型的过程,自动拆箱时编译器会调用intValue(),doubleValue()将对象转成原始类型值

了解基本类型缓存机制

缓存机制

Java为了使得八大基本数据类型具有面向对象的性质,增添了其对应的包装类。而装箱、拆箱则是为了它们之间的互相转换,jdk1.5后,编译器完成了自动装箱和拆箱的功能。

装箱:基本类型封装为包装类型。自动装箱(通过valueOf方法实现),比如Integer i1 = 128;
拆箱:包装类型简化为基本类型。自动拆箱(通过xxvalue方法实现),比如int a = new Integer(100);

从jdk1.5时,Java为了节省内存,提高性能,为Integer等包装类(除了float和double两种浮点类型)增加了缓存机制,即当变量的值在一定范围内,变量将会共用同一个对象,除了Integer类,其他所有整数类型的类都有类似的缓存机制,下面是类的缓存范围:

Integer: −128-127
Byte:−128-127
Short:−128-127
Long:−128-127
Character:0~127

缓存只有在自动装箱过程中才起作用

缓存机制实现
当编译器检测到需要将基本数据类型转换成包装类型时,自动调用valueOf方法进行自动装箱。可以看到在Integer中的valueOf方法中,如果值处在缓存范围(IntegerCache.low~IntegerCache.high)时,则直接返回内部类IntegerCache中静态成员cache数组中的Integer对象,否则返回new生成的对象,这也是为什么缓存机制只在自动装箱时才起作用。

  public static Integer valueOf(int i) {
            if (i >= IntegerCache.low && i <= IntegerCache.high)
                return IntegerCache.cache[i + (-IntegerCache.low)];
            return new Integer(i);
        }

接下来看一下Integer的内部类IntegerCache的代码,相当于一个工具类。可以看到缓存下界low为-128,上界high可以通过设置虚拟机相关参数来改变(但最小为127),然后根据上下界声明并且初始化了一个Integer数组cache,在valueOf方法中以直接返回此cache中的Integer对象。

 private static class IntegerCache {
            static final int low = -128;
            static final int high;
            static final Integer cache[];
    
            static {
                // high value may be configured by property
                int h = 127;
                String integerCacheHighPropValue =
                    sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
                if (integerCacheHighPropValue != null) {
                    try {
                        int i = parseInt(integerCacheHighPropValue);
                        i = Math.max(i, 127);
                        // Maximum array size is Integer.MAX_VALUE
                        h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
                    } catch( NumberFormatException nfe) {
                        // If the property cannot be parsed into an int, ignore it.
                    }
                }
                high = h;
    
                cache = new Integer[(high - low) + 1];
                int j = low;
                for(int k = 0; k < cache.length; k++)
                    cache[k] = new Integer(j++);
    
                // range [-128, 127] must be interned (JLS7 5.1.7)
                assert IntegerCache.high >= 127;
            }
    
            private IntegerCache() {}
        }

了解基本类型的储存方式

java中数据在内存中是如何存储的

基本数据类型

java的基本数据类型共有8种,即int,short,long,byte,float,double,boolean,char(注意,并没有String的基本类型 )。这种类型的定义是通过诸如int a = 3;long b = 255L;的形式来定义的。如int a = 3;这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。

另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。比如: 我们同时定义:

int a=3; int b=3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b这个引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。

定义完a与b的值后,再令a = 4;那么,b不会等于4,还是等于3。在编译器内部,遇到时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。


JVM的内存区域组成

java把内存分两种:

一种是栈内存,另一种是堆内存

(1)在函数中定义的基本类型变量(即基本类型的局部变量)和对象的引用变量(即对象的变量名)都在函数的栈内存中分配;

(2)堆内存用来存放由new创建的对象和数组以及对象的实例变量(即全局变量)。

在函数(代码块)中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的内存空间;

在堆中分配的内存由java虚拟机的自动垃圾回收器来管理

堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

熟悉常见修饰符

访问修饰符
Java基础复习第一天
非访问修饰符
abstract

static

finnal

synchronized

volatile 修饰符:volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个 volatile 对象引用可能是 null。

常见问题(以下问题要求能够口述出来)

Java 和 C++的区别?

  • 都是面向对象的语言、都支持封装、继承和多态
  • 在Java中没有指针这一概念,只有引用
  • Java中有垃圾自动回收机制,C++中则需要程序员手动释放、
  • Java中的类是单继承的,C++支持多重继承;虽然类不可用多继承,但接口可以多继承
  • 在C++中,字符串或字符数组最后都会有一个’\0’来表示结束,Java中没有结束符这一概念

import java 和 javax 有什么区别?

在之前Java API所必需的包是以java开头的包,javax只是作为一个扩展包、但是随着时间的推移,javax逐渐成为了Java API的一部分。因为将javax扩展包移动到java包太麻烦了,会破坏一些现有的代码,因此决定javax包成为Java API的一部分
所有实际上,javax和java没有区别。这都是一个名字。

为什么说 Java 语言“编译与解释并存”?

Java语既具有编译型语言的特征,又具有解释型语言的特征,一个java程序在类加载过程中,会被类编译器编译成一个字节码文件,再由java解释器对字节码进行解释运行,因此我们可以认为java语言是“编译与解释并存”。

高级编程语言按照程序的执行方式分为编译型和解释型两种。简单来说,编译型语言是指编译器针对特定的操作系统将源代码一次性翻译成可被该平台执行的机器码;解释型语言是指解释器对源程序逐行解释成特定平台的机器码并立即执行。比如,你想阅读一本英文名著,你可以找一个英文翻译人员帮助你阅读,
有两种选择方式,你可以先等翻译人员将全本的英文名著(也就是源码)都翻译成汉语,再去阅读,也可以让翻译人员翻译一段,你在旁边阅读一段,慢慢把书读完。

字符型常量和字符串常量的区别?

  1. 形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符
  2. 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)
  3. 占内存大小 字符常量只占 2 个字节; 字符串常量占若干个字节 (注意: char 在 Java 中占两个字节)

标识符和关键字的区别是什么?

标识符:在我们定义一个类、一个方法、一个变量时得取名字来对其每个对象进行标识、于是就有了标识符,简单来说,标识符就是名字

关键字:但是有一些标识符,java已经对其赋予了特殊的含义,只能用于特定的地方,这种特殊的标识符就是关键字

例如:在我们的日常生活中 ,“警察局”这个名字已经被赋予了特殊的含义,所以如果你开一家店,店的名字不能叫“警察局”,“警察局”就是我们日常生活中的关键字。

continue、break、和return的区别是什么?

continue:指跳出当前的这一次循环,进入下一个循环

break:指跳出本次循环体,继续执行循环体下面的语句

return:用于跳出所在方法,结束该方法的运行

Java泛型了解么?什么是类型擦除?介绍一下常用的通配符?

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。

常用的通配符为: T,E,K,V,?

  • ? 表示不确定的 java 类型
  • T (type) 表示具体的一个java类型
  • K V (key value) 分别代表java键值中的Key Value
  • E (element) 代表Element

==和equals的区别

== : 它的作用是判断两个对象的地址是否相等,即判断两个对象是不是同一个对象(基本数据类型比较的是值,引用数据类型比较的是地址)
equals() : 它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。equals()方法存在于Object类中,而Object类是所有类的直接或间接父类。

equals() 方法存在两种使用情况:

  • 情况 1:类没有覆盖 equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。使用的默认是 Object类equals()方法。
  • 情况 2:类覆盖了 equals()方法。一般,我们都覆盖 equals()方法来两个对象的内容相等;若它们的内容相等,则返回 true(即,认为这两个对象相等)。

总结:

==对于基本类型来说比较的值、对于引用类型来说比较的是引用 也就是地址值

而equals不能用于比较基本数据类型的变量,默认情况下是引用比较,不过很多类重写了equals方法,比如Integer、String等把它变成了值比较,所以一般情况下equals比较的是值是否相等。

hashCode()与 equals()相关问题

hashCode()是什么?

hashCode是一个散列值,就是把一个值通过hash函数处理得到的一个散列值的过程,是一个int整数,有了这个值我们就可以在map中对这个key-value进行对应了

为什么要有 hashCode?

hashCode在hashMap中可以将传入的值进行排序。放入数组中,当出现哈希冲突(就是不同的两个键值对对应相同的hashCode值)时,引入了链表。当到达8位时就转为二叉树

我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode?
当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

为什么重写 equals 时必须重写 hashCode 方法?

如果两个对象相等,则 hashcode 一定也是相同的。两个对象相等,对两个对象分别调用 equals 方法都返回 true。但是,两个对象有相同的 hashcode 值,它们也不一定是相等的 。因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖。

为什么两个对象有相同的 hashcode 值,它们也不一定是相等的?

因为 hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓哈希碰撞也就是指的是不同的对象得到相同的 hashCode)

相关标签: java