Java基础
2024-06-10 18:30:07 13 举报
AI智能生成
Java基础是Java编程语言的核心内容,涵盖了变量、数据类型、运算符、条件语句、循环结构、数组、函数、类、对象和异常处理等方面的知识。Java文件通常以.java为扩展名,且需要经过编译和运行两个步骤。Java语言具有跨平台、面向对象、分布式、多线程、安全等特点,被广泛应用于web开发、移动应用开发、大数据处理和科学计算等领域。
作者其他创作
大纲/内容
类和对象的区别和联系类是抽象的,概念的,代表一类事物,它是一种数据类型。对象是具体的,实际的,代表一个具体事物。类是对象的模板,对象是类的一个个体,对应一个实例。
对象在内存中的存在形式
基本介绍:概念或者叫法上,成员变量、属性,field都可以。属性是类的一个组成部分,一般是基本数据类型,当然也可以是引用类型,如对象,数组。
注意事项和细节属性的定义语法同变量:访问修饰符 属性类型 属性名;属性的定义类型可以为任意类型,包含基本类型和引用类型;属性如果不赋值,有默认值,规则和数组一致。
属性(成员变量)
先声明,在创建。
直接创建。Cat cat=new Cat();
如何创建对象
基本语法:对象名.属性名;
如何访问属性
类与对象
方法引入及调用机制分析
成员方法的功能【为什么要有方法】:提高代码的复用性。可以将实现的细节封装起来,然后供其他用户调用即可。
方法定义:形参列表:表示成员方法输入。返回数据类型:表示成员方法输出,void表示没有返回值。方法主体:表示为了实现某一功能代码快。return: 有返回值时,必须有。没有返回值时,可以有,但后面不能加返回值,如return ;(此时没有意思,一般省略)
注意事项和使用细节一个方法只有一个返回值。返回类型可为任意类型,基本类型,引用类型都可以。有返回数据时,必须有return,返回值类型必须一致或兼容。方法名:建议驼峰法,见名知意。方法是有修饰符的,用来表明方法可供使用的范围,共4种(后面细讲)使用方法时,形参和实参,保持一致,类型一致或兼容,个数,顺序必须一致。方法体内不能在定义方法,即不能嵌套定义。方法内可以进行方法调用。
方法的调用:同类方法,直接调用。不同类方法,对象名调用。跨类的方法调用还与方法的修饰符有关,后面详讲。
成员方法
基本类型数据,传递的是值(值拷贝),形参的任何改变不影响实参。
引用数据类型,传递的是引用(也可以说是值,这个值是地址),可以通过形参影响实参。
成员方法传参机制
基本介绍:简单的说:递归就是方法自己调用自己,每次调用时传入不同的变量。递归有助于编程者解决复杂问题,同时可以让代码变得简洁。
递归能够解决的问题
递归在内存中的运行机制
经典案例:阶乘、斐波那契数列、老鼠出迷宫(二维数组,递归)、汉诺塔、八皇后这几个案例,由浅入深,尤其是老鼠出迷宫后3个,还是可以深入研究一下的。
递归
基本介绍:java中允许同一类中,多个同名方法的存在,但要求形参列表不一致。好处:减轻了起名、记名的麻烦。
注意事项和使用细节:方法名:必须相同。参数列表:必须不同(参数类型或个数或顺序,至少有一样不同,参数名无要求)。返回类型:无要求。
重载(overload)
基本概念:java允许将同一个类中多个同名同功能但参数个数不同的方法,封装成一个方法。
基本语法:访问修饰符 返回类型 方法名(数据类型... 形参名){}
注意事项和使用细节:可变参数的实参可以为0或任意多个。可变参数的实参可以为数组,它的本质就是数组。一个形参列表中只能出现一个可变参数,且必须在参数的最后一个(可变参数可以和普通类型的参数一起放在形参列表)。
可变参数
基本使用:(变量作用域)java编程中,主要的变量就是属性(成员变量)和局部变量(一般是指成员方法中定义的变量)。作用域的分类:全局变量:也就是属性,作用域为整个类体。局部变量:除了属性之外的其它变量,作用域为定义它的代码块中。全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。
作用域
基本介绍:构造方法又叫构造器,是类的一种特殊的方法,它的主要作用是完成对新对象的初始化。特点:方法名和类名相同。没有返回值。在创建对象时,系统会自动的调用该类的构造器完成对象的初始化。
基本语法:修饰符 方法名(形参列表){方法体;}构造器的修饰符可以默认;构造器没有返回值;方法名和类名字必须一样;参数列表和成员方法一样的规则;构造器的调用由系统完成。
注意事项和使用细节:一个类可以定义多个不同的构造器,即构造器重载。构造器是完成对象的初始化,而不是创建对象。如果没有定义构造方法,系统会自动生成一个默认无参构造方法。可通过javapz指令反编译.class文件查看。一旦定义之后,就不会有默认的无参构造方法了,如果想使用,需要手动添加。
心得:看到这部分,这些设计的东西,是有一定规律或者说法的,不是想当然来的。比如,默认一个无参构造,是为了满足基础的对象创建,如果定义了新的构造方法,自然不需要默认定义(可有可无)。 在无参构造的语法设计上,没有返回值,且不需要写void,这样只通过此处,就能给普通方法区分。 再加上与类名相同,这样系统调用构造器的时候,可以直接匹配上对应构造器。 构造器通过重载,来满足多种需要。 很巧妙。
构造器
什么是this?java虚拟机会给每个对象分配this,代表当前对象。主要解决问题:使用this解决构造器中变量命名问题。
感觉图上画的有些乱,可以认为this是堆中对象的一个属性即可。相比于生活中我的用法。
this关键字的注意事项和使用细节this关键字可以用来访问本类的属性、方法、构造器。this用于区分当前类的属性和局部变量。访问成员方法的语法:this.方法名(参数列表);访问构造器语法:this(参数列表);注意只能在构造器中使用,且放在第一行。this不能在类定义的外部使用,只能在类定义的方法中使用。
习题思考:用Double作返回数据类型,可以接收null。解决double接受返回值的局限性。
this
面向对象编程(基础部分)
ide(集成开发环境)其他工具-eclipseeclipse是一个开放源代码的,基于java的可扩展开发平台。最初由ibm公司耗资3000万美金开发的下一代ide开发环境。2001年11月贡献给开源社区。是目前最优秀的java开发ide之一。
下载、安装
背景、字体设置等。
自定义模板:file->settings->editor->live templates->
打出首字母就能联想出一整条语句,还显示了每条语句的使用频率。
codota代码智能提示插件
每次都会在右下角弹窗提示,帮助快速熟悉快捷键。
key promoter x快键键提示插件
codeglance 显示代码缩略图插件
lombok 简化臃肿代码插件
alibaba java coding guidelines 阿里巴巴代码规范检查插件
sonarlint代码质量检查插件
常用插件
IDEA
三大作用:区分相同名字的类。当类很多时,方便管理。如api文档。控制访问范围。
基本语法:package com.bear;pachage 关键字,表示打包。com.bear 包名。
包的本质:创建不同的文件夹来保存类文件。
包的命名命名规则:数字、字母、下划线,数字不能开头,不能是关键字或保留字。命名规范:一般是小写,公司名、项目名、业务模块名;
常用包:java.lang.* 基础包,默认引用。java.util.* 工具包,如scanner。java.net.* 网络包。java.awt.* 界面开发包,GUI。
注意事项和使用细节:package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package;import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
包
基本介绍:java提供四中访问控制修饰符号,用来修饰控制方法和属性(成员变量)的访问控制权限。公开级别:public 修饰,对外公开。受保护级别:用protected修饰,对子类和同一包中的类公开。默认级别:没有修饰符号,向同一个包的类公开。私有级别:用private修饰,只有类本身可以访问,不对外公开。
使用注意事项:修饰符可以用来修饰类中的方法和属性,还可以修饰类(不过只有默认和public两种,遵循上面访问特点)。方法的访问规则和属性完全一样。
访问修饰符
基本介绍:封装就是把抽象出来的数据【属性】和对数据的操作【方法】封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作【方法】,才能对数据进行操作。
封装的理解和好处隐藏实现细节。可以对数据进行验证,保证安全合理。
封装的实现步骤:将属性进行私有化private[不能直接修改属性]提供一个公共的set方法,用于对属性判断并赋值public void setXxx(类型 参数名){//加入数据验证的业务逻辑属性=参数名;}提供一个公共的get方法,用于获取属性的值public XX getXxx(){return xx;}
封装
继承基本介绍继承可以解决代码复用,让我们的编程更加接近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
继承的基本语法class 子类 extends 父类{}子类就会自动拥有父类定义的属性和方法。父类又叫超类,基类。子类又叫派生类。
使用细节:子类继承了所有的属性和方法,在子类中私有属性是不能直接访问的,可以通过公共的方法去访问。子类必须调用父类的构造器,完成父类的初始化。当创建子类对象时,不管使用子类的哪一个构造器,默认情况下总是会调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super显示的去指定使用父类的哪一个构造器完成父类的初始化工作,否则编译器不会通过。如果希望指定调用父类的哪一个构造器 ,可显示调用。super使用时,需要构造器第一行。super和this都只能放在构造器第一行,因此这两个方法不能共存在一个构造器中。java所有类都是object的子类,object是所有类的基类。父类构造器的调用不限制于直接父类,将一直往上追溯到object类。子类最多只能继承一个父类(直接继承),即java中是单继承机制。不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。
基本介绍:super代表父类的引用,用于访问父类的属性、方法、构造器。
基本语法:访问父类的属性,方法,都不能访问带有private修饰。用super.调用。访问父类构造器:只能放在构造器的第一句,且只能有一句。
super与this
super关键字
基本介绍:简单说,方法重写就是子类有一个方法,和父类(包含间接父类)的某个方法(名称,返回类型,参数)一样,那么就说这个子类的方法重写了父类的方法。
注意事项和细节:子类的方法的参数、方法名称,和父类完全一样。子类的返回类型与父类一样,或者是父类返回类型的子类。子类方法不能缩小父类方法的访问权限。
方法重写与重载的对比
方法重写【覆盖】
继承
多态基本介绍方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础上的。
方法的多态:重写和重载的体现。
对象的多态:一个对象的编译类型和运行类型可以不一致,编译类型在定义对象时就确定了,运行类型是可以变化的(在运行时确定)。编译看左边,运行看右边。 Animal animal= new Dog();
多态的具体体现
多态的向上转型:本质:父类的引用指向了子类的对象。语法:父类类型 引用名= new 子类类型();特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员(遵守访问权限)。不能调用子类中的特有成员(在编译阶段能调用哪些成员,是由编译类型来决定的)。最终运行效果看子类的具体实现!
多态的向下转型:语法:子类类型 引用名=(子类类型)父类引用。只能强转父类的引用,不能强转父类的对象。要求父类的引用必须指向的是当前目标类型的对象(把Dog强转给Animal,不能用Cat接收)。可以调用子类类型中的所有成员(满足编译阶段调用成员的原则)。
属性没有重写直说,属性的值看编译类型。
instanceOf比较操作符,用于判断对象的运行类型是否为xx类型或是其子类型。
动态绑定机制当调用对象的方法时,该方法会和对象的内存地址【运行类型】绑定。当调用对象的属性时,没有动态绑定机制,哪里声明,哪里使用。
多态注意事项和细节多态的前提:两个对象存在继承关系。
多态
hashCode方法提高具有哈希结构的容器的效率。两个引用,如果指向是同一个对象,哈希值肯定是一样的。两个引用,如果指向的是不同对象,则哈希值是不一样的。哈希值主要是根据地址号来的,但是不能完全将哈希值等价于地址。
toString方法基本介绍 默认返回:全类名+@+哈希值的十六进制(查看object类的toString方法)。子类往往重写toString方法,用于返回对象的属相信息。当直接输出一个对象时,toString方法会被默认的调用。
finalize方法当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。垃圾回收机制的调用,是由系统来决定(即它有自己的GC算法),也可以通过System.gc()主动出发垃圾回收机制。
Object类详解
断点调试介绍:在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后可以一步步往下调试,调试过程中可以看各个变量当前的值,出错的话,调试到出错的代码行即显示错误,停下。进行分析从而找到这个bug.
提示:在断点调试过程中,是运行状态,是以对象的运行类型来执行的。断点调试能帮助查看java底层源代码的执行过程,提高java水平。
进入jdk源码的方法
debug
面向对象编程(中级部分)
static变量保存:在class实例的尾部。class对象在堆中。所以static变量在堆中。jdk7以上版本,静态域存储于定义类型的class对象中,class对象如同堆中其他对象一样,存在于gc堆中。(有说法静态域在方法区中..jdk版本有关系)
共识:static变量是同一类所有对象共享。static类变量,在类加载的时候就生成了。
什么是类变量类变量也叫静态变量【静态属性】,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
如何定义类变量定义语法: 访问修饰符 static 数据类型 变量名;访问修饰符和static位置可以互换。
如何访问类变量类名.类变量名(推荐)对象名.类变量名注意:静态变量的访问修饰符权限和普通一样。
什么时候需要用到类变量当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量);
类变量与实例变量【普通属性】区别类变量是该类的所有对象共享的,而实例变量是每个对象独享的。
加上static称为类变量【静态变量】,没有就是实例变量【普通变量,非静态变量】
类变量可以通过类名.类变量名(推荐)或者对象名.类变量名来访问(满足访问权限和范围)
实例变量不能通过 类名.类变量名方式访问。
类变量在类加载时就初始化了,也就是说,即使没有创建对象,只要类加载了,就可以使用类变量了。
类变量的声明周期是随类的加载开始,随着类消亡而销毁。
使用注意事项和细节讨论
类变量
类方法基本介绍类方法也叫静态方法。访问修饰符 static 数据返回类型 方法名(){}推荐static 访问修饰符 数据返回类型 方法名(){}
类方法调用:类名.类方法名或者对象名.类方法名(满足修饰符访问权限)
使用场景:当方法中不涉及到任何和对象相关的成员,则可以讲方法设计成静态方法,提高开发效率。常见:工具类中的方法。
注意事项和细节讨论类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法去:类方法中无this的参数 普通方法中隐含着this的参数。类方法可以通过类名调用,也可以通过对象名调用。普通方法和对象有关,需要通过对象名调用,不能通过类名调用。类方法中不允许使用和对象有关的关键字,比如this和super。普通方法都可以。类方法【静态方法】中只能访问静态变量或静态方法。普通成员方法,既可以访问普通变量(方法)也可以访问静态变量(方法)。
类方法
深入理解main方法main方法是虚拟机调用。java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public。java虚拟机在运行main方法时不必创建对象,所以该方法必须是static。该方法接收string类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数。java hello第一个参数,第二个参数 (在main方法中,打印args,可打印参数值。hello是类名)
特别提示:在main()方法中,我们可以直接调用main方法所在类的静态方法或静态属性。但是不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员。
main方法
基本介绍代码化块又称为初始化块,属于类中的成员(即类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来,但是和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调用,而是加载类时,或创建对象时隐式调用。
注意事项和细节讨论static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。类什么时候被加载? 1、创建对象实例。 2、创建子类对象实例。 3、使用类的静态成员(静态属性、静态方法)时。普通的代码块,在创建对象实例时,会被隐式的调用,被创建一次,调用一次。如果是使用类的静态成员时,普通代码块并不会执行。
4.创建一个对象时,在一个类中调用顺序是:调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态属性初始化,则按它们定义的顺序调用)。调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按它们定义的顺序调用)。调用构造方法。
5.构造方法(构造器)的最前面其实隐含了super()和调用普通代码块。静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。
6.创建一个子类时,它们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如:父类的静态代码块和静态属性(优先级一样,按定义顺序执行)。子类的静态代码块和静态属性(优先级一样,按定义顺序执行)。父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)。父类的构造方法。子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)。子类的构造方法。
7.静态代码块只能调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
注意事项和细节讨论
代码块
什么是设计模式?静态方法和属性的经典使用。设计模式是在大量的时间中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
什么是单列模式(单个的实例)所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。单例模式有两种方式:1)饿汉式 2)懒汉式
单例模式应用实例构造器私有化=>防止直接new创建。类的内部创建对象。向外暴露一个静态的公共方法。getInstance();
饿汉式vs懒汉式二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。饿汉式不存在线程安全问题,懒汉式存在线程安全问题。饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。应用场景:javaSE标准类中,java.lang.Runtime就是经典的单例模式。
static在设计模式中应用
final可以修饰类、属性、方法和局部变量;
在某些情况下,程序员可能有以下需求,就会使用final:当不希望类被继承时,可以用final修饰。当不希望父类的某个方法被子类覆盖【重写】时,可以用final关键字修饰。当不希望类的某个属性的值被修改,可以用final修饰。public final double TAX_RATE=0.08当不希望某个局部变量被修改时,可以使用final修饰。final double TAX_RATE=0.08
注意事项和细节讨论final修饰的属性又叫常量,一般用xx_xx_xx命令。final修饰的属性在定义时,必须赋初始值,并且以后不能再修改,赋值可以在:定义时;在构造器中;在代码块中,三个位置。如果final修饰的属性是静态的,则初始化的位置只能是定义时;在静态代码块中;不能在构造器中。final类不能继承,但是可以实例化对象。如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。final不能修饰构造方法(即构造器)。final和static往往搭配使用,效率更高,底层编译器做了优化处理。搭配使用,不会进行类加载。包装类,String都是final类。
final关键字
当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法(用abstract关键字修饰该方法),那么这个类就是抽象类(用abstract来修饰该类)。
抽象类的介绍用abstract关键字修饰一个类,这个类叫做抽象类。用abstract关键字修饰一个方法,这个方法叫做抽象方法。抽象的价值更多作用在于设计,是设计者设计好后,让子类继承并实现抽象类。抽象类,在框架和设计模式中使用较多。抽象类可以有任意成员(抽象类本质还是类),比如非抽象方法、构造器、静态属性等等。抽象方法不能有主体,即不能实现。如果一个类继承了抽象方法,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。抽象方法不能使用private final static修饰,因为这些关键字都是和重写相违背的。
抽象类的应用:模板设计模式
抽象类
面向对象编程(高级)
arrayList
vector
linkedList
list
linkedHashSet
hashset
treeSet
set
collection
LinkedHashMap
hashMap
properties
hashTable
treeMap
map
集合框架体系
游标hasNext()判断集合中下一位置是否有值。next()返回游标下一位置的值,并将游标下移。
注意点:如果使用迭代器,对集合进行遍历之后,此时游标在集合的最下方。想再次遍历集合,需要给游标重新赋值,重新获取集合迭代器即可。
iterator
简易版的迭代器,它的底层就是调用的迭代器。
注意点:可用于集合,也可用于数组。
增强for
遍历方式
普通for
使用冒泡结合集合中设置元素的方法完成。
排序
List
可以放null值,可以放多个null值。
底层实现为数组,可从源码中获得。
基本与vector相同,线程不安全的集合,效率高,但是不建议在多线程中使用。
注意事项
arrayList中维护了一个object类型的数组elementData。transient object【】elementData; // transient表示瞬间,短暂的表示该属性不会被序列化。
扩容使用的是Array.copyOf();这样可以保留原来的数据,在保留原来数据的基础上扩容。
注意:idea有可能会打断点无法进入。需要设置:如图。
当创建arrayList对象时如果使用的是无参构造器,则初始elementData容量为0,第一次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。
底层结构与源码分析
ArrayList
vector底层也是一个对象数组,protected Object[] elementData;
vector是线程同步的,即线程安全的,vector类的操作方法带有synchronized修饰。但注意并不是需要线程安全,就一定要使用vector,如果这个集合,仅在一个线程运行,那么完全可以使用arrayList,这样效率更高。
vector底层结构与arrayList相同,都是数组。而底层的源码实现逻辑相同,只有细微区别:synchronized,扩容相关。
linkedList底层维护了一个双向链表
linkedList中维护了两个属性first和last分别指向首节点和尾节点。
每个节点(Node)对象,里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表。
基于底层的结构,linkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高(没有扩容处理)。
底层结构
注意:因为LinkedList是双向链表,进行集合操作时,其实操作的是pre和next。
源码分析
LinkedList改查的时候,是从头开始。
与arrayList的应用场景对比
LinkedList
无序,没有索引,但是每次取出的时候,顺序是固定的,它的底层是有一定算法的。不允许元素重复,允许存在null,但是只能存在一个。
遍历方式:迭代器。增强for。
hashSet的底层其实是hashMap,它在源码里直接调用了hashMap(数组+链表+红黑树)。为什么不直接使用数组,而是加上了链表。。 为了提高效率。
hashSet底层是HashMap
添加一个元素时,先得到hash值(不是hashcode值,hashcode值经过一个算法得到的结果值)-》会转成索引值。
找到存储数据表table,看这个索引为止是否已经存放有元素如果没有,直接加入。如果有,调用equals(可自行重写定义)比较,如果相同,就放弃添加,如果不同,则添加到最后。
添加元素的底层机制
hashSet底层是hashMap,第一次添加时,table数组扩容到16,临界值(threshold)是 16×加载因子(loadFactor)是0.75=12
如果table数组使用到了临界值12,就会扩容到16*2=32,新的临界值就是32*0.75=24以此类推
font color=\"#ff0000\
注意事项:临界值12,不是说table中的数据达到12,而是说node的总值达到12.比如索引1上有7个元素,索引2上有6个元素,其他都为null,那么此时也会进行扩容。
扩容与树化转成红黑树的机制
hashSet
linkedHashSet是HashSet的子类;linkedHashSet底层是一个linkedHashMap,底层维护了一个数组+双向链表。linkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序(使用entry(不是node)中的before和after将插入的相邻元素连接起来),这使得元素看起来是以插入顺序保存的。
底层机制:在linkedHashSet中维护了一个hash表(数组table)和双向链表(linkedHashSet有head和tail相当于hashset的first和end)。每个节点都有before和after属性,这样可以形成双向链表。(注意也可以说成pre和next)在添加一个元素时,先求hash值,在求索引,确定该元素在hash表中的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加【原则和hashset一样】)tail.next=newELement;// 简单指定 newElement.pre=tail; tail=newElement;通过以上,我们遍历linkedHashSet也能确保插入顺序和遍历顺序一致。
linkedHashSett
基本介绍:有序的不重复的集合【底层个 使用了treeMap】当我们想有序排列时,可在构造方法中传入一个比较器(匿名内部类)。在匿名内部类中制定排序规则,需要注意的是,如果两个元素,按照制定的排序规则,比较为相同时,会不再添加该元素。比如,当使用字符串的长度进行排序,那么元素:a,ab,ac。3个元素,ac会加不进去。
当我们使用无参构造方法创建treeSet时。没有传入比较器时,如果集合中的对象实现类了Comparator接口,那么在调用比较器,进行排序时是没有问题的,如String对象。如果是定义的对象如Student。需要实现Comparator接口,否则,会报错。classCastExeption
单列接口
迭代器
keyset+map.get(key)
values
entrySet
遍历
概要:hashMap是map接口使用频率最高的实现类。hashMap是以k-v对的方式来存储数据(hashMap$node类型)key不能重复,但是值可以重复,允许使用null键和null值,如果添加相同的key,则会覆盖原来的k-v,等同于修改。(key不会被替换,value会被替换),阅读源码可得。与hashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的。(jdk8的hashMap底层 数组+链表+红黑树)hashMap是线程不安全,没有实现同步互斥,方法上没有synchronized关键字。
hashMap底层机制-扩容【与hashset相同,其实hashset底层原理就是hashmap】hashMap底层维护了Node类型的数组table,默认为null。当创建对象时,将加载因子(loadfactor)初始化为0.75。当添加key-value,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等,则直接替换value;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。第一次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)。以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即24,以此类推。在java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树)。
注意点:当table中达到临界值(table长度×0.75)会触发扩容。还有一种情况是,当table中在一个索引位置上,也就是一个链表上,达到8个之后且table的长度不够64,此时不会去树化,而是先去扩容,直到table的长度达到64。
基本介绍:properties类继承自hashTable类并且实现了map接口,也是使用一种键值对的形式来保存数据。它的使用特点和hashTable类似。properties还可以用于从xxx.properties文件中,加载数据到properties类对象,并进行读取和修改。注意:xxx.properties文件通常作为配置文件,这个知识点在io流举例。
基本介绍:有序的不重复的集合当我们想有序排列时,可在构造方法中传入一个比较器(匿名内部类)。在匿名内部类中制定排序规则,需要注意的是,如果两个元素,按照制定的排序规则,比较为相同时,会不再添加该元素。比如,当使用字符串的长度进行排序,那么元素:a,ab,ac。3个元素,ac会加不进去。
双列接口
经典接口
主要取决于业务操作特点,然后根据集合实现类特性进行选择。1)先判断存储的类型(一组对象【单列】或一组键值对【双列】)2)一组对象:collection接口 允许重复:list 增删多:linkedList【底层维护了一个双向链表】 改查多:arrayList【底层维护object类型的可变数组】 不允许重复:set 无序:hashSet【底层个是hashMap,维护了一个哈希表即(数组+链表+红黑树)】 排序:treeSet 插入和取出顺序一致,linkedHashSet,维护数组+双向链表3)一组键值对:map 键无序:hashMap【底层jdk7:数组+链表jdk8:数组+链表+红黑树】 键排序:treeMap 插入和取出顺序一致:LinkedHashMap,维护数组+双向链表 读取文件:properties
集合常用场景
排序操作:reverse(list):反转list中元素的顺序shuffle(list):对list集合元素进行随机排序sort(list):根据元素的自然顺序对指定list集合元素按升序排序sort(list,Comparator):根据指定的Comparator产生过的顺序对list集合元素进行排序swap(list,int i,int j):将指定list集合中的i处元素和j处元素进行交换
查询、替换操作:object max(collection):根据元素的自然顺序,返回给定集合中的最大元素object max(collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素object min(collection)object min(collection,Comparator)int frequency(collection,object)返回指定集合中指定元素的出现次数void copy(List dest,List src):将src中的内容复制到dest中boolean replaceAll(List list,Object oldvalue,Object newValue):使用新值替换List对象的所有旧值
collections
集合
95年发布第一个版本
java之父-詹姆斯·高斯林 (James Gosling)
现在公司使用更多的版本:java8、java11
所属公司:之前所属sun公司,后被甲骨文收购。
Java历史
JavaSE(Java Standard Edition)标准版支持面向桌面级应用(如Windows下的应用程序)的java平台,提供了完整的Java核心API,此版本以前成为J2SE
JavaEE(Java Enterprise Edition)企业版是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中包含的技术如:Servlet、Jsp等,主要针对于Web应用程序开发。版本以前称为J2EE
JavaME(Java Micro Edition)小型版支持Java程序运行在移动终端(手机、PDA)上的平台,对JavaAPI有所精简,并加入了针对移动终端的支持,此版本以前成为J2ME曾火过一段时间,后期受安卓影响较大。
Java技术体系平台
Java是面向对象的(oop)
Java语言是健壮的。Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。
Java语言是跨平台性的。【即一个编译好的.class文件可以在多个系统下运行,这种特性称为跨平台】
Java语言是解释型的【了解】解释型语言:JavaScript、php、java 编译型语言:c、c++区别:解释型语言,编译后的代码,不能直接被机器执行,需要解释器来执行,编译型语言,编译后的代码,可以直接被机器执行。
Java的特性
nodepad++、editplus、sublime、idea、eclipse
Java常用工具
Java运行机制及运行过程Java语言的特点:跨平台性 因为有了JVM,同一个Java程序在三个不同的操作系统(windows、linux、mac)中都可以执行(针对三种系统,有3个版本Jvm,Jvm负责对class文件进行解释执行),这样就实现了Java程序的跨平台性。
Java虚拟机基本介绍Jvm是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器,包含在JDK中。对于不同的平台,有不同的虚拟机。Java虚拟机机制屏蔽了底层运行平台的差别,实现了\"一次编译,到处运行\"。
JDK、JRE基本介绍JDK的全称(Java Development Kit Java开发工具包),JDK=JRE+Java的开发工具包【java、javac、Javadoc、javap等】。JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包含了JRE。JRE(Java Runtime Environment Java运行环境),JRE=JVM+Java的核心类库【类】。包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机只需要安装JRE即可。
用户变量:电脑当前用户生效系统变量:所有用户生效
安装、配置
JDK
运行有了可执行的java程序(Hello.class字节码文件)通过运行工具java.exe对字节码文件进行执行,本质就是.class装载到jvm机执行。(注意:如果Hello.java源文件需要重新编译,生成新的class文件后,在进行执行,才能生效)。
注意细节:一个源文件中最多只有一个public类,但是其他类的个数不限。编译后,每一个类对应一个class文件。源文件名必须与public的类名对应。
快速入门
可读性,为己为人
单行注释//
注释中的内容不会被Jvm执行
多行注释中不允许嵌套多行注释。
多行注释/**/
注释内容可以被jdk提供的工具javadoc所解析,生成一套以网页文件形式体现的该程序的说明文档,一般写在类。基本格式/** @author*/生成对应的文档注释:javadoc -d 文件夹名 -xx -yy Demo3.java举例:javadoc -d D:\\\\temp -author Demo3.java 生成一个文档注释,位置在d盘下的temp文件中,生成的标签有author,其他标签不生成,对应的java类为Demo3。
文本注释
注释
类、方法的注释要以javadoc的方式来写。
非javadoc的注释,一般是给代码的维护者看的,着重告诉读者为什么这样写,如何修改,注意什么问题,一般用单行、多行注释。
注释代码的格式:使用tab右移,使用shift+tab左移。
运算符和=两边习惯各加一个空格。
源文件使用utf-8编码,如果是dos窗口javac、java命令操作文件时,为了能阅读,它的编码是gbk。
代码行宽度不要超过80字符。idea中有个右竖线,按照那个就可以。
代码编写次行风格{在方法名同行(推荐)和行尾风格{另起一行。
代码规范(基础版)
dos介绍:disk operating system磁盘操作系统。
常用dos命令查看当前目录有什么: dir切换到其他盘: cd切换到当前盘:cd 绝对路径,cd 相对路径切换到上一级:cd ..切换到根目录:cd \\查看目录下的所有文件夹:tree 目录清屏:cls退出:exit
了解其他命令,主要操作都在linux系统中,而且命令会发生变化,此处了解即可。md【创建目录】rd【删除目录】copy【拷贝文件】copy+文件名+拷贝到的目录以及新文件名 del【删除文件】move【剪切】echo【输入内容到文件】echo ok->hello.txt 创建一个hello.txt内容为oktype【控内容到文件】type nul->hello.txt 创建一个hello.txt内容为空
如图举例: ..\\ 上一级目录
相对路径-绝对路径
dos命令
Java概述
为什么需要变量?不论是使用那种高级程序语言编写程序,变量都是其程序的基本组成单位。
概念变量相当于内存中一个数据存储空间的表示,可以把变量看做一个房间的门牌号,通过门牌号可以找到房间,而通过变量名可以访问到变量值。变量的使用步骤声明变量 int a; 赋值 a=4;或者int a=4;
注意事项:变量表示内存中的一个存储区域【不同的变量,类型不同,占用的空间大小不同】比如int4个字节,double就是8个字节。该区域有自己的名称【变量名】和类型【数据类型】变量必须先声明,后使用,即有顺序该区域的数据可以在同一类型范围内不断变化。(重新赋值)变量在同一个作用域内不能重名。变量=变量名+值+数据类型,变量三要素。
变量介绍
当左右两边都是数值型时,则做加法运算
当左右两边有一方为字符串,则做拼接运算
运算顺序,从左到右
+号
整数类型,存放整数(byte【1】,short【2】,int【4】,long【8】)
浮点(小数)类型(float【4】,double【8】)
数值型
字符型(char【2】)
布尔型(boolean【1】),存放true,false
基本数据类型
类(class)
接口(interface)
数组【】
引用数据类型(面向对象再讲)
类型体系
整型基本介绍
整数类型的使用细节:Java各整数类型有固定的范围和字段长度,不受固定OS【操作系统】的影响,以保证Java程序的可移植性。Java的整型常量默认为int型,声明long型常量须后加‘l’或‘L’Java程序中变量常声明为int型,除非不足以表示大数,才使用longbit:计算机中最小存储单位。byte:计算机中基本存储单元1byte=8bit【二进制中详讲】。
整型
浮点型基本介绍
浮点型
使用细节字符常量是用单引号''括起来的单个字符允许使用转义字符'\\'来将其后的字符转变为特殊字符型常量,如char c='\'; \表示换行符。char本质是一个整数,在输出时,是unicode码对应的字符。http://tool.chinaz.com/Tools/Unicode.aspx可直接给char赋一个整数,然后输出时,会按照对应的unicode字符输出。38889 对应韩 char类型是可以进行运算的,相当于一个整数,因为它都对应有unicode码。'a'+1 直接输出为字符int('a'+1)输出为整数。
本质探讨字符型 存储到计算机中,需要将字符对应的码值(整数)找出来,比如'a' 存储:'a'->码值97->二进制->存储;读取:二进制->97->'a'->显示字符和码值的对应关系是通过字符编码表决定的(是规定好的)
ASCII码介绍:上世纪60年代,美国指定了一套字符编码(使用一个字节),对英语字符与二进制位之间的关系做了统一规定。这被称为ASCII码码。ASCII码码一共规定了128个字符的编码,只占用了一个字节的后面7位,最前面的1位统一规定为0。【注意:此处表示,一个字节是可以表示256个字符的,ASCII码只用了128个字符】缺点:不能表示所有字符。
utf-8编码介绍(了解)utf-8是互联网上使用最广的一种unicode的实现方式。utf-8是一种变长的编码方式。它可以使用1-6个字节表示一个符号,根据不同的符号而变化字节长度。使用大小可变的编码,字母占用1个字节,汉字占用3个字节。
字符编码表的介绍ASCII(ASCII编码表 一个字节表示,一个128个字符)unicode固定大小的编码,使用两个字节来表示字符,字母和汉字统一都占用两个字节,这样浪费空间。utf-8大小可变的编码,字母使用1个字节,汉字使用3个字节gbk可以表示汉字,而且范围广,字母使用1个字节,汉字2个字节gb2312可以表示汉字,gb2312<gbkbig5码繁体中文,台湾,香港
字符型
基本介绍也叫boolean类型,只允许取true\\false,无null占1个字节适于与逻辑运算,一般用于程序流程控制。if while do-while for
布尔型
类型详讲
数据类型
基本介绍:当java程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数据类型,这个就是自动类型转换。char->int->long->float->doublebyte->short->int->long->float->double
自动类型转换注意和细节:有多种类型的数据混合运算是,系统首先自动将所有数据转换成容量最大的那种数据类型,在进行计算。当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据会报错,反之就会进行自动类型转换。font color=\"#ff0000\
自动类型转换
基本介绍:自动类型转换的逆过程,将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符(),但可能造成精度降低或溢出,格外要注意。(int)1.9 是精度降低,得到了1;(byte)2000,是溢出,得到的是-48。
细节说明:只针对最近的操作数有效,往往会使用小括号提升优先级(int)(10*3.5)char类型可以保存int的变量值,但不能保存int的变量,需要强转【这个正常呀,注意一下】。
强制类型转换
基本介绍:在程序开发中,我们会经常将两者互相转换。
基本类型--》String:将基本类型的值+\"\"。
String--》基本类型:通过基本类型的包装类调用parseXx方法即可。Integer.parseInt(\"123\");Double.parseDouble(\"123.1\");依次有byte、short、long、float、boolean。字符特殊一些 Char.charAt(0);将字符串第一个位置的元素转为字符。
注意事项:将String转换为基本类型,注意String的值,“123”可以,“hello”自然就不行,会抛出异常。
基本数据类型和String类型的转换
类型转换
变量
算术运算符
赋值运算符
关系运算符【比较运算符】
逻辑运算符
位运算符【需要二进制基础】
三元运算符
运算符体系
一览图
一览图注意:运算符\"==\"不要误写成\"=\"
关系运算符
||短路或与逻辑或|类比'与'即可。
赋值运算符的分类:基本赋值运算符:=复合赋值运算符:+= -= *= /= %=等。
赋值运算符特点:从右往左:int num=a+b+c;左边只能是变量,右边可以是变量、表达式、常量值。复合赋值运算符a+=3;等价于a=a+3; 且具有强转效果(byte类型+=3;可以)
一览表运算符有不同的优先级,所谓优先级就是表达式运算中的运算顺序。如上图,上一行的运算符总优于下一行。使用时,用括号比较实用。
运算符的优先级
运算符详讲
标识符概念:Java对各种变量、方法和类等命名时使用的字符序列称为标识符。凡是自己可以起名字的地方都叫标识符。
关键字一览表1)
关键字一览表2)
保留字一览表
标识符的命名规则(必须)26个英文字母大小写,0-9,_或者$组成。数字不可以开头。不可以使用关键字和保留字,但能包含关键字和保留字。严格区分大小写,长度无限制。标识符不能包含空格。
命名规范(建议)包名:多单词,都小写类名、接口名:多单词首字母都大写,大驼峰。变量名、方法名:小驼峰。常量名:所有字母都大写,单词间下划线分隔。
标识符
用来接收用户输入的数据。导入该类所在包。创建该类的对象。调用里面的功能。
键盘输入语句
进制介绍,对于整数有四种表示方式:二进制:0、1,满二进一,以0b或0B开头。十进制:0-9,满十进一。八进制:0-7,满八进一。以数字0开头表示。十六进制:0-9以及A(10)-F(15),满十六进一。以0x或0X开头表示。此处A-F不区分大小写。
其他进制转十进制:规则:从最低位(右边)开始,将每个位上的数提取出来,乘以该进制的(位数-1)次方,然后求和。
十进制转其他进制:规则:将该数不断除以该进制,直到商为0为知,然后将每部得到的余数倒过来,就是对应的该进制数。如34转为二进制数是0b100010.
二进制转换成八进制规则:从低位开始,将二进制每3位一组,转成对应的八进制数即可。
二进制转换成十六进制规则:从低位开始,将二进制每4位一组,转成对应的十六进制数即可。
八进制转换成二进制:规则:将八进制数每1位,转换成对应的一个3位的二进制数即可。
十六进制转换成二进制:规则:将十六进制数每1位,转换成对应的一个4位的二进制数即可。
进制转换
进制
位运算的思考:>> <<等等。
二进制在运算的中的说明:二进制是逢2进位的进位制,0、1是基本算符。现代的电子计算机技术全部采用的是二进制,因为它只使用0、1两个数字字符,非常简单方便,易于用电子方式实现。计算机内部处理的信息,都是采用二进制数来表示的。二进制(binary)数用0和1两个数字及其组合来表示任何数。进位规则是“逢2进1”,数字1在不同的位上表示不同的值,按从右至左的次序,这个值以二倍递增。
案例1
案例2
案例3
位运算符1)
位运算符2)
位运算(了解)
运算符
顺序控制
单分支
双分支
多分支
嵌套分支(不超过3层,可读性不好)
if、if-else、if-else if-else
基本语法:switch关键字,表示switch分支。表达式对应一个值。case 常量1:当表达式的值等于常量1,就执行语句块1。break:表示退出switch。如果和case常量1匹配,就执行语句块1,如果不匹配,就继续匹配case常量2。此处需要注意case穿透,如果没有break,一直向下执行。如果都没有匹配,则执行default。
注意事项和细节讨论表达式数据类型,应和case后的常量类型一致,或者是可以自动转成可以相互比较的类型,比如输入的是字符,而常量是int。switch(表达式)中表达式的返回值必须是:byte short int char enum Stringcase 子句中的值必须是常量,不能是变量,可以是表达式。
switch
如果判断的具体数值不多,而且符合byte short 等6种类型。虽然两个都可以使用,建议使用switch语句。
其他情况,如区间判断,boolean类型判断,使用if,if的使用范围更广。
swith与if的比较
分支控制
基本语法:for(循环变量初始化;循环条件;循环变量迭代){循环操作(语句);}
编程思想:化繁为简先死后活
for
while
基本语法:循环变量初始化;do{循环体(语句);循环变量迭代;}while(循环条件);先执行,再判断,也就是说,一定会执行一次。
dowhile
将一个循环放到另一个循环体内,也就是嵌套循环。一般两层,最多不超过3层,可读性差。
多重循环
循环控制
break语句出现在多层嵌套的语句块中,可以通过标签指明要终止的是哪一层的语句快。break 语句可以指定退出那一层,不指定时为最近的循环体。循环语句。上的label1: 为标签名。实际开发中,尽量不适用标签。
break
continue语句使用细节与break一致,区别在于continue语句用于结束本次循环,继续执行下一次循环。
continue
return使用字方法,表示跳出所在的方法(如果方法是main方法,会退出程序)。
return
控制结构
使用方式1-动态初始化数组的定义:数组类型【】数组名=new 数组类型【大小】;数组的引用: 数组名【下标或者叫索引】
使用方式2-动态初始化先声明,再创建。数据这类型 数组名【】;数组名=new 数据类型【大小】;注意 数组名和【】,两个顺序谁在前都可以。
数组方式3-静态初始化数据类型 数组名 【】={元素值,元素..}
值传递与引用传递的区别
数组的赋值机制基本数据类型赋值,值传递【值拷贝】数组类型赋值,引用传递(赋的值是地址)
数组的使用
数组的翻转
原理:数组的扩容等,都是复制原有数组,创建新的数组,效率是很低的。
注意点:创建新的数组之后,之前的数组,在堆中没有指引之后,会被Jvm回收。
数组的扩容、缩减
数组
内部排序:指将需要处理的所有数据都加载到内部存储器中进行排序。包括(交换式排序法、选择式排序法、插入式排序法)
外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序。包括(合并排序法、直接合并排序法)
排序的分类
基本思想:通过对待排序序列从后向前(从下标较大的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从前移向后部,就像水底下的气泡一样向上冒。
冒泡排序法
经典排序
顺序查找(挨个,从头到尾比较)
二分法查找(算法时讲解)
查找
使用方式1:动态初始化语法:类型【】【】数组名=new 类型【大小】【大小】。举例:int arr [][]=new int[2][3].
使用方式2:动态初始化先声明在开辟空间。类型 数组名[][];数组名= new 类型【大小】【大小】。
使用方式3:列数不确定。
二维数组的使用
二维数组的内存图
声明方式:int [] [] yint [] y []int y [] []
二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不同。
二维数组使用细节和注意事项
二维数组
数组、排序、查找
Java基础
0 条评论
回复 删除
下一页