Java基础
idea快捷键
- 删除当前行 ctrl+D
- 复制当前行 ctrl+shift+向下箭头
- 补全代码 alt+ /
- 添加注释 ctrl+ /
- 导入改行需要的类:先配置auto import,再使用alt+enter
- 快速格式化代码 ctrl+alt+L
- 快速运行程序 alt+R
- 生成构造器等 alt+insert
- 查看一个类的层级关系 ctrl+H
- 将光标放在一个方法上,输入ctrl+B,可以定位方法
- 自动分配变量名,通过在后面加.var
idea模板
- pvsm/main
- sout
- fori
包
- com.公司名.项目名.业务模块名
- 包名规范:都是小写,不能数字开头,不能含有保留字或关键字
- package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package
- import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求
常用的包:
java.lang.* // lang包是基本包,默认引入,不需要再引入
java.util.* // util包,系统提供的工具包,工具类,使用Scanner
java.net.* // 网络包,网络开发
java.awt.* //是做java的界面开发,GUI
访问修饰符
java提供四种访问控制修饰符,用于控制方法和属性(成员变量)的访问权限(范围)
- 公开级别:用public修饰,对外公开
- 受保护级别:用protected修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开
- 私有级别:用private修饰,只有类本身可以访问,不对外公开
同类就是本类
setName(name); 等价于this.setName(name);
- 注意事项
- 修饰符可以用来修饰类中的属性,成员方法以及类
- 只有默认的和public才能修饰类!并且遵循上述访问权限的特点
- 成员方法的访问规则和属性完全一样
封装
封装就是把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作
setter和getter可以通过快捷键alt+insert快速生成set和get方法,在这些方法里可以设置一些验证的方法来判断用户输入的值是否符合要求。
但是如果在构造器中没有设置验证方法,则通过构造器生成的对象有可能是不符合要求的,解决方法:将构造方法与set方法结合,即在构造器中调用set方法
继承
在编程领域,谁是谁的子类可以是指多层关系。比如D是A的子类,这是跨越了两层
继承的基本语法:
class 子类 extends 父类{
- 子类就会自动拥有父类定义的属性和方法
- 父类又叫做超类,基类
- 子类又叫派生类
}
-
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
-
子类必须调用父类的构造器,完成父类的初始化(先调用父类的构造器,再调用子类的)
其实是因为在子类构造器的第一行会默认调用super();即便我们不写在运行的时候程序也会默认自动先运行它
- 在创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
Java核心技术卷I
4.1 面向对象程序设计概念
- 面向对象程序设计(Object-Oriented Programming,简称OOP)
- 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。程序中很多对象来自标准库,还有一些是自定义的。
- 面向对象的程序是先考虑数据结构,再考虑操作数据的算法
- 面向过程适用于规模较小的问题,而面向对象更加适用于解决规模较大的问题,因为多个方法和属性可以封装在一个类中,相对来查找问题的时候会快速一些。
- 由类构造(construct)对象的过程称为创建类的实例(instance)。对象中的数据称为实例域(instance field),操纵数据的过程称为方法(method),对于每个特定的类实例(对象)都有一组特定的实例阈值。这些值的集合就是这个对象的当前状态(state)。无论何时,只要向对象发送一个消息,它的状态就有可能发生改变
- 实现封装的关键在于绝对不能让类中的方法直接访问其他类的实例域。程序仅通过对象的方法与对象的数据进行交互。封装给对象赋予了“黑盒”特征,这是提高重用性和可靠性的关键
- OOP的另一个原则是:用户可以通过扩展一个类来建立另外一个新的类,在Java中,所有类都源自一个超类Object。扩展后的新类具有所扩展的类的全部属性和方法。在新类中,只需提供适用于这个新类的新方法和数据域就可以。通过扩展一个类来建立另外一个类的过程称为继承。
- 对象的三个主要特性:
- 对象的行为(behavior)
- 对象的状态(state)
- 对象标识(identity)
- OPP中首先从设计类开始,然后再往每个类中添加方法
- 类之间常见的三种关系
- 依赖(use-a):一个类的方法操纵另一个类的对象(应该减少依赖,即类之间耦合度降低)
- 聚合(has-a):类A的对象包含类B的对象
- 继承(is-a):如果类A扩展类B,类A不但包含类B继承的方法,还会拥有一些额外的功能
很多程序员采用UML(Unified Modeling Language,统一建模语言)绘制类图,用来描述类直接之间的关系,类用矩形表示,类之间的关系用带有各种修饰的箭头表示
-
一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。任何对象变量的值都是对存储再另外一个地方的一个对象的引用。new操作符的返回值也是一个引用。
Date birthday = new Date(); Date deadline; //定义了一个对象变量,它可以引用Date类型的对象,但是此时它不是一个对象, //也没有引用对象,所以不能使用Date中的任何方法 String s = deadline.toString(); //编译错误 //必须首先初始化变量deadline deadline = new Date(); //或者引用一个已存在的对象 deadline = birthday;
-
可以显式地将对象变量设置为null ,表明这个对象变量目前没有引用任何对象。如果一个方法应用在一个值为null地对象上,那么就会产生运行时错误 deadline = null; String s = deadline.toString();//运行错误
力扣刷题
数组
public static void test_arr() {
int[][] arr = {{1, 2, 3}, {3, 4, 5}, {6, 7, 8}, {9,9,9}};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println(arr[3]);
}
输出的地址为:
[I@7852e922
[I@4e25154f
[I@70dea4e
[I@5c647e05
java是没有指针的,同时也不对程序员暴露其元素的地址,寻址操作完全交给虚拟机,如上输出的地址:数值为16进制,但不是真正的地址,而是经过处理过后的数值。可以看出,二维数组的么一行头结点的地址是没有规则的,更谈不上连续。
所以java中二维数组可能如下排列:
但是在c++中因为有指针,二维数组的排列方式是连续的:
题一:二分查找
思路:用left和right来定义边界,这里用闭包的形式[left, right]
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){
int middle = left+(right - left) / 2;
if(target == nums[middle]){
return middle;
}else if(target < nums[middle]){
right = middle - 1;
}else if(target > nums[middle]){
left = middle + 1;
}
}
return -1;
}
}
题二:搜索插入位置
//暴力遍历数组的方法,时间为O(N)
class Solution {
public int searchInsert(int[] nums, int target) {
for(int i = 0; i < nums.length-1; i++){
//因为数组是按照升序的方式排列的,按照数组的顺序查找,只要满足target比一个元素小或等于(同时解决相等的值),即找到了对应的位置
if(target <= nums[i]){
return i;
}
}
//当target是数组中最大的时候,就输出数组的长度
return nums.length;
}
}
//二分查找法,时间为O(logn)
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right){
int middle = left + (right - left) / 2;
if(target < nums[middle]){
right = middle - 1;
}else if(target > nums[middle]){
left = middle + 1;
}else{
return middle;
}
}
//当数组中没有,走到这一步,一定是因为不再满足条件:left<=right,
//即此刻为:right<left,造成这样的原因是因为在上一步:target应该在这两个数之间,
//所以返回left或者right+1
return left;
}
}