java概念知识点总结
一、基础语法
- java内存模型和内存区域以及执行过程理解
- 特例: 基本类型(八大基本类型(boolean、char、byte、short、int、long、float、double)
1) 因为对于一些小的、简单的变量,在new中创建对象往往不是很有效,于是设置了基本类型
2) java中所有不带小数点的类型都默认是int类型,带小数点的默认类型为double类型long类型后面要加l(因为默认是int类型),float类型后面加F,double类型后加D(为了区别float和double)
3) java中所有基本类型都有固定的内存大小,不随机器硬件架构的变化而变化
4) 所有的数值类型都有正负号,所以不要去寻找无符号的数值类型
5) boolean类型所占存储空间的大小没有明确指定,仅定义为能够取字面值true和false - 引用类型(类、接口、数组)
- 垃圾回收器:因为在堆中创建的对象不能自动释放,所以java中有个垃圾回收器,用来监视用new创建的所有对象,并辨别那些不会再被引用的对。随后,释放这些对象的内存空间,以便供其他新的对象使用
- 基本成员默认值:若类的某个成员是基本数据类型,即使没有进行初始化,java也会确保它获得一个默认值。当变量作为类的成员使用时,java才确保给定其默认值。所以上述初始化不适用于局部变量(即并非某个类的字段)
- 方法的基本组成:名称、参数、返回值
- Java语言最大的特点:跨平台性(一次编译,多次执行,一般Window下开发,在Linux下面部署)
- 拆箱和装箱:装箱就是将基本类型转换为对象类型,拆箱就是将对象类型转换为基本类型。
二、方法和数组
- 访问控制符:
1)private:这个成员只能在当前类的内部被访问
2)default:可以被相同包下的其它类访问
3)protected:可以被同一个包中中的其他类访问,也可以被不同包中的子类访问
4)public:可以被所有类访问
java不同访问修饰符总结(必看) - 访问修饰符: 定义为static,则强调只有一份,定义为final,则说明是个常量
1)static关键字:
通常来说,当创建类时,就是在描述那个类的对象的外观和行为。除非用new创建那个类的对象,否则,实际上并未获得任何对象。有两种情形是上述情况无法解决的,一种情况是,只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少对象,甚至根本不创建任何对象。另一种情况是,希望某个方法不与包含它的类的任何对象关联在一起,也就是说,即使没有创建对象,也能够调用这个方法。通过static可以满足这两方面的需要。
static方法就是没有this的方法,所以不能调用非静态方法和非静态成员
static静态变量和非静态变量的区别:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
只有类才存在静态的变量 方法只能对静态变量的操作 不能在方法内试图定义静态变量 否则的话会抛出编译错误 静态变量的本意是为了让所有的对象共享这个变量,如果在方法里面定义静态变量的话就存在逻辑错误了,也达不到你想要目的. 因为在方法定义静态变量根本没有他的任何意义. 任何对象都有自己的方法,即使是静态方法,方法内的变量也是在方法调用时候才开始分配内存,所以想给成静态的在逻辑上存在问题
2)final:
对于基本类型,final使数值恒定不变;用于对象引用,final使引用恒定不变。一旦引用被初始化指向一个对象,就无法再把它改为指向另一个对象。
final修饰方法表示该方法不能被重写和继承,可以关闭动态绑定
当将某个类的整体定义为final时,就表明了你不打算继承该类,也不允许别人这么做,由于final类禁止继承,所以final类中所有的方法都隐式指定为是final,因为无法覆盖它们。
final和private关键字:类中所有的private方法都隐式地指定为是final的。由于无法取用private方法,所以也就无法覆盖它。可以对private方法添加final修饰词,但这并不能给该方法增加任何额外的意义。
3)如果一个域被定义为static final,则这个域就是一个静态常量。不能省略任何一个关键字,若是少了static,则该域变成了一个实例域,需要由类对象对其进行访问。若是省略了final,则该域变成了静态域,静态方法可以对其进行修改。 - 数组初始化·:
1) int []a=new int[10];
2) int []a={10,11,12};
3) new int[]{10,11,12}; - 对于数组,new只是为其分配内存空间,并不创建对象
interface U
{
void play();
void drink();
void eat();
}
class B
{
private U[] us;
B(int i)
{
us=new U[i];
}
}
5. 数组工具类Arrays 方法 描述
toString(array) 将传入的数组转换为字符串
equals(array1,array2) 比较两个数组是否相等
sort(array) 对指定的数据进行排序
deepEquals(Object[] a1,Object[] a2) 比较两个指定数组彼此是否深层相等
binarySearch() 二分法查抄数组
copyOf() 复制数组
copyOfRange() 将指定数组的指定范围复制到一个新数组
三、面向对象
- 面向对象四大特点:
1)抽象: 抽象就是将一类实体的共同特性抽取出来。重新进行封装或者说封装到新的类中。
2)继承:继承是一种连接类的层次模型,继承的目的在于鼓励重用。
3)封装:封装是把过程和数据包围起来。对数据的访问只能通过已定义的界面。
4)多态:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。
重载(overloading)与重写(override)的区别:
1)重载发生在同一个类,不同的方法里面。 重写发生在父子类中,签名完全相同的方法里面。 2)重载参数签名不同,而重写相同且返回类型相同。
3)方法名相同,重写override是父类与子类之间多态性的一种表现,重载overload是一个类中多态性的一种表现。
-
类和对象的区别:
1) 类是用来描述实体的“模板”或者原型;
2) 对象是实际的实体,每一个对象都是类的一个具体实例。
3) 类用来定义对象所有的属性和方法,同一类的所有对象都拥有相同的特征和操作;
4) 可以将类理解成生成产品的模具,而对象则是根据此模具生产的一个个产品。 - 复用类(java编程思想第7章)
1) 组合
2) 继承 - 构造器
构造器命名的原因(了解):对于构造器命名有两个问题,第一,所取的任何名字都可能与类的某个成员名称相冲突;第二,调用构造器是编译器的责任,所以必须让编译器知道应该调用哪个方法。因此,构造器的命名也就顺理成章了(由于构造器的名称必须与类名完全相同,所以“每个方法首字母小写”的编码风格并不适用于构造器)。构造器没有返回值(这与返回void不同)。
构造器的特点如下:
1) 构造器与类同名
2) 每个类可以有一个以上的构造器
3) 构造器可以有0个,1个或者多个参数。
4) 构造器没有返回值
5) 构造器总是伴随着new操作一起调用 - 初始化实例域有三种方式:
1) 构造器中初始化
2) 声明的时候初始化
3) 通过初始化块初始化:用大括号包含起来的代码块。只要构造器执行就会调用该代码块: - 初始化的顺序
1) 所有数据域被初始化为默认值(0,false,null)
2) 按照在类声明中的出现次序,执行所有在类中出现的初始化语句和初始化块
3) 如果构造器的第一行调用的其他的构造器,则执行其他被调用的构造器
4) 执行构造器的初始化主体 - 在传参的过程中,如果传入的数据类型(实参)小于方法中声明的形式参数类型,实际数据类型就会被提升,char类型略有不同,如果无法找到恰好接收char型的参数,会直接提示至int型
- 参数传递:java语言中方法调用只有按值调用一种方式。也就是说方法得到的是参数值的拷贝。方法不能修改传递给他的任何参数变量的内容。
注意: 对于8种基本数据类型、String对象,采用复制一份传递到方法中的方式,方法中无法修改传递的内容本身。 对于引用类型(类类型,数组类型),java传递的是地址,可以修改地址引用位置的数据内容,但不能修改地址本身。 - Java中提供的包主要有以下3种用途:
1) 将功能相近的类放在同一个包中,可以方便查找与使用。
2) 由于在不同包中可以存在同名类,所以使用包在一定程度上可以避免命名冲突。
3) 在Java中,某次访问权限是以包为单位的。
访问其他包中的public类可以有以下两种方法:
1)使用长名引用包中的类
2)使用import类语句引入包中的类 - 关于面向的对象的概念:
关于多态的几个问题解析
构造函数中super()关键字思考
子类能继承父类的私有属性和方法吗
java面向对象必看知识
四、最终类、抽象类和接口
java中有final修饰的类为最终类:
1. 最终类 :
1)不能被继承
2)由final关键字修饰的方法为最终方法,最终方法不能被覆盖(重写)
3)最终方法和最终类没有必然的关系
2. 抽象类 :
抽象象类具有如下的特点:
1)抽象类必须被继承
2)抽象类不能被直接实例化,他只能作为其他的超类,这一点和final类正好相反
3. 抽象方法具有如下的特点:
1) 抽象方法必须为public或者protected
2) 抽象方法必须被重写
3) 抽象方法只有声明,不能有实现
4) abstract void fun();
5) 定义了抽象方法的类必须是抽象类
4. Object类
Object类是java中所有类的始祖。在java中每个类都是由他扩展而来。但我们并不需要显示的extends Object方式来声明。我们在定义类的时候,如果没有明确的指定超类,则Object类被默认认为为该类的超类。
Object的toString方法内容如下:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
5. 接口:
1)接口不是类,而是对类的一组需求描述。
2)在java中是单继承模式,一个类只能继承一个父类。但是可以实现(implements)一个或者多个接口。
6. 接口的主要特点如下:
1)接口中的成员变量默认都是public static final类型的,方法都是public abstract类型的。
2) 接口中只能有public static final类型的变量和public abstract类型的方法;没有明确指定的时候,系统默认会给加上相应的内容。
3) 接口没有构造方法,不能被实例化。
4) 一个接口不能实现另一个接口,但它可以继承多个其他接口。
5) 与子类继承抽象父类类似,实现接口的类必须实现接口的所有方法,除非该类显示的标明为抽象类。
6) 一个类只能继承一个直接的父类,但能实现多个接口。
7. 接口和抽象类的区别:
1)
抽象类只能被继承,而且只能单继承。
接口需要被实现,而且可以多实现。
2)
抽象类中可以定义非抽象方法,子类可以直接继承使用。
接口中都有抽象方法,需要子类去实现
3)
抽象类使用的是 is a 关系。
接口使用的 like a 关系。
4)
抽象类的成员修饰符可以自定义。
接口中的成员修饰符是固定的。全都是public的。
五、内部类:
- 内部类是指在一个外部类的内部再定义一个类。类名不需要和文件夹相同。
- 内部类可以是静态static的,也可用public,default,protected和private修饰。(而外部顶级类即类名和文件名相同的只能使用public和default)。
- 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。
- 内部类可以访问其外围类的方法和字段。这是因为当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。这就是为什么需要先创建外围类对象才能创建内部类对象。
- 当内部类被声明为private时,就没办法直接获得内部类的引用(外部类类名.内部类类名),所以此时可以通过接口来访问内部类,此时可以实现更好的封装。
- 局部内部类(在方法和作用域内的内部类)
- 匿名内部类 :匿名类没有名字的类 ,封装性好,比较安全,用了一次便可以丢弃
注意:匿名内部类如果要使用一个在外部类定义的对象(包括基本类型),则要声明参数是final的,否则编译时会出错。 - 嵌套类(了解):如果不需要内部类对象与其外围类对象之间有联系,可以将内部类声明为static,这称为嵌套类。
注意:普通的内部类对象隐式地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static时,就不是这样了。嵌套类意味着:1)要创建嵌套类的对象,并不需要其外围类的对象 2)不能从嵌套类的对象中访问非静态的外围类对象 - 内部类的好处:
1) 每个内部类都能独立继承一个接口的实现,所以无论外部类是否已经继承某个接口的实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整。
2)方便将存在一定逻辑联系的类组织在一起
3)方便编写事件驱动程序
4)方便编写线程代码
六、异常和异常处理
- 在程序运行时经常会出现一些非正常的现象,如死循环、非正常退出等,称为运行错误。根据错误性质将运行错误分为两类:错误和异常。
1)致命性的错误
如程序进入了死循环,或递归无法结束,或内存溢出,这类现象称为错误。错误只能在编程阶段解决,运行时程序本身无法解决,只能依靠其他程序干预,否则会一直处于非正常状态。
2)非致命性的异常
如运算时除数为0,或操作数超出数据范围,或打开一个文件时,发现文件并不存在,或欲装入的类文件丢失,或网络连接中断等,这类现象称为异常。在源程序中加入异常处理代码,当程序运行中出现异常时,由异常处理代码调整程序运行方向,使程序仍可继续运行直至正常处理。 -
- 一个异常经历抛出,捕获,处理的过程:
1)抛出(throw):创建一个异常类对象的过程。
2)捕获(catch):获得异常对象的过程。
3)处理:对异常对象进行相关操作的过程。 - 异常(Exception)分为哪几种?有什么区别?
受检异常:编译器能够检测出来,并要求必须处理的异常
RunTimeException非受检异常:编译器不要求必须处理的异常 - 异常常见面试题
七、集合框架
- java容器类类库的用途是保存对象,有两个不同的概念:
1) Collection
一个独立的元素序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复元素。Queue按照排队规则来确定对象产生的顺序(通常它与被插入的顺序相同)
2)Map
一组成对的“键值对”对象,允许你用键来查找值。ArrayList允许用数字来查找值,因此从某种意义上说,它将数字和对象关联在了一起。映射表允许我们使用另一个对象来查找某个对象,它也被称为关联数组。 - 添加一组元素:
1)Arrays.asList()方法接受一个数组或是用逗号分隔的元素列表,并将其转换为一个list对象
2)Collections.addAll()方法接受一个Collection对象,以及一个数组或是用逗号分割的列表,将元素添加到collection中 - 打印:
1)调用容器提供的toString()方法。Collection打印内容用方括号括住。Map用大括号括住。 2)容器中的toString方法实现Arrays.toString(list.toArray()) - 迭代器:
原因:要使用容器,必须对容器的确切类型编程。但考虑下面这种情况:如果原本是对着List编码的,但是后来发现如果能够把相同的代码应用于Set,将会显得非常方便。迭代器统一了对容器的访问方式
java中的Iterator只能单向移动,这个Iterator只能用来:
1)使用方法iterator()要求容器返回一个Iterator。
2)使用next()获得序列的下一个元素
3)使用hasnext()检查序列中是否还有元素
4)使用remove()将迭代器新近返回的元素删除 - List
1)ArrayList:长于随机访问元素,但是在List中间插入和移除元素较慢
2)LinkList:通过代价较低的在List中间插入和删除操作,但是对于随机访问较慢 - Set
1)HashSet:HashSet使用了散列
2)TreeSet:TreeSet将元素存储在红-黑树数据结构中,和HashSet不同的是TreeSet以有序的方式保存添加的数据。 - Map
1)HashMap:采用Hash算法来决定每个元素的存储位置。
2)TreeMap:实现是红黑树算法的实现
八、IO
- java类库中的I/O类分成输入和输出两部分。通过继承,任何自Inputstream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写单个字节或字节数组。但是,我们通常不会用到这些方法,他们之所以存在是因为别的类可以使用他们,以便提供更有用的接口。因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能(这是装饰器设计模式)。实际上,Java中“流”类库让人迷惑的主要原因在于:创建单一的结果流,却需要创建多个对象。
九、字符串
详解见《java编程思想》十三章 字符串
十、类型信息
- 类型信息在运行时是由称为class对象的特殊对象完成的,它包含了与类有关的信息。
- 类是程序的一部分,每个类都有一个class对象。换言之,每当编写并且编译了一个新类,就会产生一个class对象(更恰当的说,是被保存在一个同名的.class文件中)。
- java多态原理(核心):Java中每个对象都有相应的class对象,因此我们随时都能通过class对象知道某个对象“真正”所属的类。无论我们对引用进行怎样的类型转换,对象本身所对应的class对象都是同一个,当我们通过某个引用调用方法时,java总能找到正确的class类中所定义的方法,并执行该class类中的代码。由于class对象的存在,java不会因为类型向上转换而迷失。
- 如果你没有一个类的对象,但想获取这个类的class对象,可以调用Class类的静态forName()方法(接受一个包含目标类的文本名的String字符串,返回一个Class对象的引用)。如果你有这个类的对象,可以调用getClass()来获得Class对象的引用。
待更新。。。