所有的java程序都是由main方法开始的
基本类型
整形
byte
- Java中最小的数据类型,在内存中占8位(bit),即1个字节,取值范围-128~127,默认值0
short
- 短整型,在内存中占16位,即2个字节,取值范围-32768~32717,默认值0
int
- 整型,用于存储整数,在内在中占32位,即4个字节,取值范围-2147483648~2147483647,默认值0
long
- 长整型,在内存中占64位,即8个字节-263~263-1,默认值0L
浮点型
float
- 浮点型,在内存中占32位,即4个字节,用于存储带小数点的数字(与double的区别在于float类型有效小数点只有6~7位),默认值0
double
- 双精度浮点型,用于存储带有小数点的数字,在内存中占64位,即8个字节,默认值0
其他
char
- 字符型,用于存储单个字符,占16位,即2个字节,取值范围0~65535,默认值为空
boolean
- 布尔类型,占1个字节,用于判断真或假(仅有两个值,即true、false),默认值false
拆箱装箱
可以将包装类Integer理解为箱子
拆箱
拆箱就是把Integer类型的数据转换为基本数据类型int
装箱
装箱就是把基本数据类型的int转换为Integer类型的数据
自动的装箱和拆箱
装箱调用的是.valueOf()方法
拆箱调用的是.intValue()方法
自动拆箱和装箱的过程是通过java编译器来做的 javac
128陷阱
128陷阱,讲的是-128-127之间的包装类型会指向同一个内存空间,因此使用==进行判定的时候会显示true
当声明的两个数不存在与这个范围之内的时候,会重新开辟一个内存空间来存储,因此使用==进行比较的时候会显示false,这个时候要使用.equals来进行比较。
因为int类型使用的比较多,所以在Integer的源码中,可以对于这个范围进行进行调整,他的下限还是-128但是上线我们可以认为的去调整。
但是在Long类型当中已经明确的表明了他的范围就是-128-127
一般来说,包装类型和基本类型混用的情况之下,会对包装类型进行自动拆箱.
int类型可以作为switch中的标记进行使用
涉及到钱的计算的使用,一般是将分作为基本单位,用整数的加减乘除去进行计算,不使用元作为基本的计算单位。
变量和常量
变量的初始值,局部变量是没有初始化的,只有类的成员变量才会被进行初始化,默认值是0,null,false;
但是对于数组来说会对于一个数组中的值进行初始化。
变量的赋值
int a = 3
类型转化问题
数值类型之间的合法转化
实线是不会造成精度丢失的,但是虚线的可能会造成精度丢失。
final
变量值大写
修饰类表明这个类不能被继承
一般会和static连用
修饰方法不能被重写
修饰变量不能被修改
引用变量的话不可以指向新的对象
防止指令重排序
常见的用final修饰的类:当一个类,我们不希望他的任何一个行为被修改的时候,我们就用final修改,比如String类
i++和++i区别
1、赋值顺序不同
++ i 是先加后赋值;i ++ 是先赋值后加;++i和i++都是分两步完成的bai。
因为++i 是后面一步才赋值的,所以它能够当作一个变量进行级联赋值,++i = a =b,即 ++i 是一个左值;i++ 的后面一步是自增,不是左值。
形象的理解可以是i++先做别的事,再自己加1,++i先自己加1,再做别的事情。
2、效率不同
比如i=3,b=i++就是说b=3,完成之后让i变成4,b=++i就是先让i++变成4,然后b=4,其中++i比i++效率要高些。一般来说在循环域里面,这两者并没有什么很大的区别,但是要注意其生存周期,以及i值在程序流中的变化。
字符串
String | StringBuffer | StringBuilder |
---|---|---|
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 | StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 | 可变类,速度更快 |
不可变 | 可变 | 可变 |
线程安全 | 线程不安全 | |
多线程操作字符串 | 单线程操作字符串 |
输入输出
输出:sout
输入:
-
Scanner a = new Scanner(System.in);
面向对象与类
什么是面向对象?
面向对象的三个特点:封装、继承、多态
自己的事情自己办,程序之间的耦合度比较低
从根本上说,只要对象能够满足要求,就不必关心他的具体实现过程。
面向过程设计?
main方法依次的调用其他方法,相互之间是耦合在一起的,某一个模块是不能单独的运行的。
类
有类型构造的对象,被称之为类的实例化。
继承父类对于类进行扩充。
更改器方法和访问器方法
get、set方法
构造函数
和类名一致
可以进行重载
不可以重写
没有返回值
一般在new后边调用
如果没有自定义的构造函数,那么java会创建一个无参构造函数
super、this
super用来调用父类的方法和构造函数,如果用父类的构造函数,需要在构造函数的第一行有效代码。
this用来调用本类的方法和构造函数
隐式参数与显式参数
方法有两种参数。第一种参数称为隐式参数,是出现在方法名前的类对象。第二种参数位于方法名后面括号中的数值,这是显式参数
- this指向 谁调用这个方法就指向谁
封装的优点
在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
java 封装,说白了就是将一大坨公共通用的实现逻辑玩意,装到一个盒子里(class),出入口都在这个盒子上。你要用就将这个盒子拿来用,连接出入口,就能用了,不用就可以直接扔,对你代码没什么影响。
对程序员来说,使用封装的目的:
1.偷懒,辛苦一次,后面都能少敲很多代码,增强了代码得复用性
2.简化代码,看起来更容易懂
3.隐藏核心实现逻辑代码,简化外部逻辑,并且不让其他人修改,jar 都这么干
4.一对一,一个功能就只为这个功能服务;避免头发绳子一块用,导致最后一团糟
方法参数
- java中都是按值传递
基于类的访问权限
- private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
- default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问。
- protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
- public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
23种设计模式
详解传送门http://c.biancheng.net/design_pattern/
方法的重写和重载
类的初始化顺序
静态变量/静态代码块 -> main方法 -> 非静态变量/代码块 -> 构造方法
静态代码块与静态变量的执行顺序同代码定义的顺序;非静态变量与代码块的执行顺序同代码执行顺序
面向对象设计
一、抽象
父类为子类提供一些属性和行为,子类根据业务需求实现具体的行为。
抽象类使用abstract进行修饰,子类要实现所有的父类抽象方法否则子类也是抽象类。
二、封装
把对象的属性和行为(方法)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节;
在java中,对于对象的内部属性一般用private来实现隐藏,并通过set和get方法对外提供访问接口。
三、继承
子类继承父类的属性和行为,并能根据自己的需求扩展出新的属性和行为,提高了代码的可复用性。
Java的继承通过extends关键字来实现,实现继承的类被称为子类,被继承的类称为父类(有的也称其为基类、超类),父类和子类的关系,是一种一般和特殊的关系;子类扩展父类,将可以获得父类的全部属性和方法。
overide:
当子父类中出现相同方法时,会先运行子类中的方法。
重写的特点:方法名一样,访问修饰符权限不小于父类,返回类型一致,参数列表一致。
多态
不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态;
具体的实现方式就是:接口实现,继承父类进行方法重写,同一个类中进行方法重载。
封装和继承都是为Java语言的多态提供了支撑;多态存在的三个必要条件:
要有继承;
要有重写;
父类引用指向子类对象。
理解方法调用
- 编译器首先查看对象声名的类型和方法名。这里需要注意方法重载(Overload),编译器会一一列举类中所有的名字为f的方法,以及的超类中名字对应的方法(可以访问的,不能访问的不算,比如超类的private方法)。至此编译器知道了所有的候选方法
- 接下来,编译器要确定方法调用中提供的参数类型。如果所有名字为f的方法存在一个与调用参数完全匹配的,就选择这个方法。比如我们调用a.m(“Jack”),编译器会选择m(String),而不是m(int)。由于存在类型的自动转换(比如byte自动转为int,子类会自动转为超类),情况会比较复杂。如果编译器没有找到类型一样的方法,或者发现经过类型转换之后可以找到多个方法与之匹配,编译器就会报错。
- 如果是private方法、static方法、final方法(final下一个小节介绍)或者构造器,那么编译器可以准确的知道应该调用哪个方法。这个叫静态绑定(static binding)。。与此对应的如果调用方法依赖于隐式参数的实际类型,那么就不是编译器的问题,而是运行期的问题,称作动态绑定。
- 当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用与x所引用对象的实际类型最合适的那个类的方法。假设x的实际类型是D,它是C类的子类。如果D类定义了方法 f(String),就直接调用它;否则,将在D类的超类中寻找f(String),以此类推。
抽象类和接口
接口的设计目的,是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为。它只约束了行为的有无,但不对如何实现行为进行限制。对“接口为何是约束”的理解,我觉得配合泛型食用效果更佳。
而抽象类的设计目的,是代码复用。当不同的类具有某些相同的行为(记为行为集合A),且其中一部分行为的实现方式一致时(A的非真子集,记为B),可以让这些类都派生于一个抽象类。在这个抽象类中实现了B,避免让所有的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现。正是因为A-B在这里没有实现,所以抽象类不允许实例化出来(否则当调用到A-B时,无法执行)。
作者:阿法利亚
链接:https://www.zhihu.com/question/20149818/answer/150169365
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
接口可以继承多个,但是类只支持单继承