(1)JDK7复习
1,JAVA的三大特性
封装性:除了基本类型数据外,其他都以对象的方式存在,对象是对数据和方法的封装体。多态性:Java中允许抽象类和接口,通过继承或者实现接口,可以实现一个方法在不同对象中有不同的行为。继承:表示子类通过继承父类,可以调用父类的属性和方法。
2,简单概述单例模式的实现
三个步骤:构造方法的私有,类加载的时候初始化一个私有的内部静态对象,提供静态返回静态方法。
3,基本类型转换为类对象的方法
1,new关键字,2,封装类的valueOf的静态方法
4,Arrays常见静态的方法
1,数组赋值fill,2,数组排序sort,3,查找数组元素binarySearch
5,List,Set,MAP接口以及常见的实现类
1,list接口的实现类:ArrayList(查询快,增删慢,线程不安全),vector(子类中有stack,线程安全效率低,查询快,增删慢),linkedList(查询慢,增删快,线程安全,支持对首位操作,可以当做队列使用)
2,set接口的实现类(不存在重复):HashSet(底层通过haskcode和equals保存唯一),TreeSet(采用红黑树存储,有序),LinkedHashSet(保留插入顺序)
3,map接口的实现类:HashMap(最多允许一个键为null,多个值为null,线程不安全),HaskTable(不允许键值为空,支持线程同步),LinkedHashMap(保留了插入的顺序),TreeMap(默认按照键值升序排列)。
4,Collections.sort()对集合进行排序。
6,String对象常见的方法
查找子串(indexOf,lastIndexOf)截取子串(substring)判断字符串是否已某段字符串开头或者是结尾(startsWith,endsWith)大小写的转换(toUpperCase,toLowerCase)。
7,基本类型与String类型的转换
1,基本数据类型转换为String类型:使用String.valueOf静态方法,基本数据类型封装成对象再用toString(),直接加上空字符串。
2,String类型转换成基本数据类型:调用基本数据类型的封装类的静态方法parseXxx(),用字符串构造基本类型对象,用字符串构造基本数据类型对象在调用封装对象的XxxValue()方法。
8,判断JAVA标识符
Character.isJavaIdentifierPart(char ch)判断一个字符是否为JAVA标识符
9,String与StringBuffer的区别
string是不变类,对string进行修改则会产生一个新对象。
10,StinrgBufer的常见静态方法
倒置(reverse),追加(append),删除(delete),插入(insert)
11,字符串的编码
String.getBytes();// 可以将字符串按照特定风格进行编码的字节数组,String(bytes[],String charset)字节数组转换为字符串。
12,MD5
Message-Digest-Algorithm 5将任意长度的字符串转换成一个128位大整数,不可逆。
13,StringTokenizer划分字符串
StringTokenizer(String str, String delim, boolean returnDelims) ,按照delim对字符串进行划分。
14,异常
1,throws出现在方法声明并且后面允许接好多异常类型。
2,try-catch-finaly中finaly区域的代码一定会执行,即使catch有return。
3,自定义异常,接口Throwable有两个实现类,Exception(程序能够捕获的异常)Error(不应捕获,如虚拟机错误)
15,线程
1,定义一个线程:继承Thead类,实现Runnable接口。
2,线程互斥:synchronized关键字修饰方法。
3,线程协作:synchronized代码区中:wait()释放锁并等待,notify或notifyALL释放锁并唤醒其他等待进程。
4,Thead.join方法
5,表示执行该进程之后才能执行join里面的方法
6,设置进程的优先级setPriority
7,定义守护进程:在start方法前面设置setDaemon
16,序列化与反序列化
Java序列化就是指把Java对象转换为字节序列的过程。
Java反序列化就是指把字节序列恢复为Java对象的过程。
17,instanceof操作符
用于比较两个对象是否类型相同(instanceof左边为具体类对象标识符,右边为类标识)
18,反射
概念:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
19,Java网络编程
主要有三种类型(基于URL网络编程,基于socke网络t编程,基于UDP数据报的网络编程)
1,基于URL网络编程:主要通过URL类获取目标和源地址的相关信息。
2,基于socket编程:步骤,服务器端通过ServerSocket对象开启一个accept等待客服端的消息,客服端根据服务器的ip地址和端口号创建一个Socket,建立与服务器端的连接。通过设置Socket的输入和输出流进行传递数据。
20,Java中的JDBC
连接数据库的步骤:
1,首先使用Class.forName方法加载数据库驱动类(要求jvm查找并加载该类),然后再用java.sql.DriverManager.getConnection方法连接数据库,返回连接的对象。
2,通过connection,createStatement()创造statement对象,executeQuery()返回一个ResultSet对象,executeUpdate()跟新。
3,动态查询(PreparedStatement既能执行静态的语句也能执行动态的语句),根据connection的 PreparedStatement prepareStatement(String sql),PreparedStatement 可以将string sql语句中的?可以对其赋值。
21,数据库连接池
将一些conncetion对象存储在vector中,要用的时候拿一个出来,用完之后归还。
22,J2SE 7.0新特性
1,switch()中可以用字符串当标识。
2,catch可以处理一个或者多个异常
3,泛型的创建可以通过类型的推断来简化。
下面两种写法都是正确的
LinkedList<LinkedList> s1=new LinkedList<LinkedList>();
LinkedList<LinkedList> s2=new LinkedList<>();
4,可以用下划线连接整数
int c1=1_2_234;System.out.println(c1);console:12234
5,try-with-resources实现自动管理资源,在jdbc中可以运用到。
6,fork/join并行新特性,用于可以分解的线程场景。
23,正则表达式
通过String对象的public boolean matches(String regex) 方法进行判断
regex元字符可以有下面这些:
.:代表任一个字符
\d:代表0-9中的任一一个数字。\D:代表任一一个非数字的字符。
\p{Lower}:代表小写字母。\p{upper}:代表任一个大写字母。\p{Digit}:表示任意数字。
[]:表示其中任意一个字符,[abc]:abc中任意一个、
[^abc]除了abc中的任一一个、[a-zA-Z]:大小写字母中任意一个
中括号中可以嵌套中括号,也支持并交差运算。
[a-d[m-p]]a-d或者m-p中的仁义一个、[a-z&&[def]]def中任意一个、[a-f&&[^bc]]代表abcded与bc的差。
限定符:
X?:X出现0或者1次、*出现0次或者多次、+出现一次或者多次
X{n}:表示出现n次、X{n,m}表示出现n次至m次、XY表示x的后缀是Y、X|Y表示x或者Y。
(2)Java SE8
1,lambda表达式
1,简介:lambda是一个带有参数的表达式:
形式:(参数)-> {代码块}
可以无参数
表达式中默认无返回值或者每种勤快情况都有返回值。
2,函数式接口
Function接口可以存储函数
3,方法的应用
对象::静态方法
类::静态方法
类::实例方法
2,接口中默认方法和静态方法
存在接口的默认方法default默认关键字,默认方法中可以具体实现。
接口存在静态方法。
3,Stream API
1,迭代器意味着特定的遍历策略,禁止了高并发。
2,可以从集合(Collection接口中有stream方法。),数组(Stream.of()静态方法,Arrays.stream()静态方法),生成器或者迭代器(StreamSupport.stream())中创建stream。
3,使用过滤器filter选择元素,使用map来改变元素。其他改变stream的操作有limit,distinct和sorted。
4,要从stream中获得结果,请使用reduction操作符,例如count、max、min、findFirst或者findAny。其中一些方法会返回一个optional值。
5,Optional类型是为了安全的代替使用null值。要想安全的使用它需要借助ifPresent和orElse方法。
6,你可以收集集合,数组,字符串或者map中stream中的结果。
7,Collections类中的groupingBy和partitioningBy方法允许你对stream中的内容进行分组,并获取每个分组的结果。
8,Java8对原始类型int、long、double提供了专门的stream。
9,,stream与集合的区别:stream不会存储元素,stream操作不会改变源对象,会返回一个新的结果的stream,stream比循环可读性更好。
10,原始类型流与对象流
原始类型流:Intstream,Longstream,DoubleStream,转换成对象流可以用boxed方法。
对象流转换成原始类型流可以用mapToInt,mapToLong或者mapToDpuble方法,在此基础上调用toArray方法获取原始类型的数组。
11,收集结果
可以将stream转换成iterator或者toArray()方法。
A[] toArray(IntFunction<A[]> generator);为了能够直接返回成目标种类的对象,可以传入构造方法,String[]::new,Integer[]::new;
collect方法用于收集结果
HashSet result=stream.collect(Collectors.toSet());
List result=stream.collect(Collectors.toList());
String result=stream.collect(Collectors.joininf());// 将流中的字符串连接起来
stream.foreach(System.out::printLn),stream.forEachOrdered();// 表示将流中数据进行遍历输出
Map<Integer,String> map=stream.collect(Collectors.tomap(i.id,i.name));
12,分组与分片
Map<String,List> a=stream.coolect(Collectors.greupingBy(Class::getVal));//按照class的getval的属性进行分组。
(3)java小技巧
1,int a[]与int []a的区别
采用int a[]这种写法,是为了沿袭C C++的写法。
在Java中为了说明所有东西都是对象常采用int[] a写法。
2,C++与JAVA函数传值的区别
3,Java集合中forEach的使用方法
1,collection接口中分forEach方法:
res.forEach(ans-> { if(ans.equals("目标")) System.out.println(ans);} );
2,map接口中的forEach方法:
map.forEach((first,second)->{System.out.println("key : " + first+ " value: " + second))})
4,返回为int[][]
可以先定义一个list<int []> res对象,最后用res.toArray(new int[0][]);的方法可以得到int[][];
(4)剑指offer
1,和为s的连续正数序列II
采用滑动窗口的思想去解决问题。
class Solution {
public int[][] findContinuousSequence(int target) {
int left = 1; // 滑动窗口的左边界
int right = 2; // 滑动窗口的右边界
int sum = left + right; // 滑动窗口中数字的和
List<int[]> res = new ArrayList<>();
//窗口的左边是窗口内的最小数字,只能小于等于target / 2,
//因为题中要求的是至少含有两个数
while (left <= target / 2) {
if (sum < target) {
//如果窗口内的值比较小,右边界继续向右移动,
//来扩大窗口
sum += ++right;
} else if (sum > target) {
//如果窗口内的值比较大,左边边界往右移动,
//缩小窗口
sum -= left++;
} else {
//如果窗口内的值正好等于target,就把窗口内的值记录
//下来,然后窗口的左边和右边同时往右移一步
int[] arr = new int[right - left + 1];
for (int k = left; k <= right; k++) {
arr[k - left] = k;
}
res.add(arr);
//左边和右边同时往右移一位
sum -= left++;
sum += ++right;
}
}
//把结果转化为数组
return res.toArray(new int[0][]);
}
}
2,构建二叉树
根据前序遍历和中序遍历构建二叉树
递归的思想解决
class Solution {
Map<Integer,Integer> mymap;
public TreeNode buildTree(int[] preorder, int[] inorder) {
mymap=new HashMap<>();
int len=preorder.length;
// 将中序遍历按照键(节点值)值(索引位置)
for(int i=0;i<len;i++)
{
mymap.put(inorder[i],i);
}
return creatTree(preorder,inorder,0,len-1,0,len-1);
}
public TreeNode creatTree(int[] preorder,int [] inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right){
if(preorder_left>preorder_right)return null;
//创建根节点
TreeNode root=new TreeNode(preorder[preorder_left]);
// 查找根节点在中序遍历的位置
int root_index=mymap.get(preorder[preorder_left]);
int left_length=root_index-inorder_left;
//得到根的左子树
root.left=creatTree(preorder,inorder,preorder_left+1,preorder_left+left_length,inorder_left,root_index-1);
//得到根的右子树
root.right=creatTree(preorder,inorder,preorder_left+left_length+1,preorder_right,root_index+1,inorder_right);
return root;
}
}
3,1~n 整数中 1 出现的次数
题目描述:计算1-n所有位数出现1的个数
class Solution {
public int countDigitOne(int n) {
int res=0;
String s = String.valueOf(n);
int len=s.length();
for(int i=len-1;i>=0;i--)//按照十进制展开 计算i位置上1出现的个数
{
int digit= (int) Math.pow(10,len-1-i);//表示哪个位置
//进行判断i位置
if(s.charAt(i)=='0')// 在i位置为0的情况下,i之前的高位可以为0-max-1,(max-1表示高位字符串值的-1),总数为max
{
int temp=0;
for(int j=0;j<i;j++)// 统计max值
{
temp*=10;
temp+=s.charAt(j)-'0';
}
res+=(digit*temp);// 所以i为0的时候,之前值逐步增加,不超过的情况下i中取得1的次数。例如:1100,当求个位数的时候,之前高位可以为00-10,不可以为11,因为11位高位时候,个位不能为1.
}
else if(s.charAt(i)=='1')
{
// 高位
int temp=0;
for(int j=0;j<i;j++)
{
temp*=10;
temp+=s.charAt(j)-'0';
}
res+=(digit*temp);
// 低位
temp=0;
for(int j=i+1;j<len;j++)
{
temp*=10;
temp+=s.charAt(j)-'0';
}
temp++;
res+=temp;
}
else{// 当前位为2-9
int temp=0;
for(int j=0;j<i;j++)
{
temp*=10;
temp+=s.charAt(j)-'0';
}
temp++;
res+=(digit*temp);
}
}
return res;
}
}
4,离散化的思想解决逆序数的问题
求一个数组的逆序数的对数?限定了数组的大小。
1,采用树状数组的思想去解决问题,把数组的值用c[]记录下来,会遇到值为负数的情况,顾若采用两个c[]分别存储政府,可是数组的最大值无法确定,会是的栈溢出OOM。
2,采用离散化的思想将一个数组中的数缩小距离地聚集起来,首先先进行复制数组,然后对复制数组进行排序,然后用Arrays.binarySearch的方法进行查找,将原数组的值用查找得到的下标替换。
System.arraycopy(nums, 0, tmp, 0, n);
// 离散化
Arrays.sort(tmp);// 从小到大进行排序
for (int i = 0; i < n; ++i) {
nums[i] = Arrays.binarySearch(tmp, nums[i]) + 1;
}
class Solution {
public int reversePairs(int[] nums) {
int n = nums.length;
int[] tmp = new int[n];
System.arraycopy(nums, 0, tmp, 0, n);
// 离散化
Arrays.sort(tmp);// 从小到大进行排序
for (int i = 0; i < n; ++i) {
nums[i] = Arrays.binarySearch(tmp, nums[i]) + 1;
}
// 树状数组统计逆序对
BIT bit = new BIT(n);
int ans = 0;
//
// for (int i = n - 1; i >= 0; --i) {
// ans += bit.query(nums[i] - 1);// 1-nums[i]-1
// bit.update(nums[i]);
// }
for(int i=0;i<n;i++)
{
bit.update(nums[i]);
ans+=(i+1-bit.query(nums[i]));
}
return ans;
}
}
class BIT {
private int[] tree;
private int n;
public BIT(int n) {
this.n = n;
this.tree = new int[n + 1];
}
public static int lowbit(int x) {
return x & (-x);
}
public int query(int x) {
int ret = 0;
while (x != 0) {
ret += tree[x];
x -= lowbit(x);
}
return ret;
}
public void update(int x) {
while (x <= n) {
++tree[x];
x += lowbit(x);
}
}
}
5,数字序列中某一位的数字
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19
位是4,等等。请写一个函数,求任意第n位对应的数字。
这是找规律的题目:
class Solution {
public int findNthDigit(int n) {
int digit = 1;// 表示位数
long start = 1;// 表示每个位数的最开始的数字
long count = 9;// 表示每个位数能最多表示的长度
while (n > count) { // 1.找到n在的位数
n -= count;
digit += 1;
start *= 10;
count = digit * start * 9;
}
long num = start + (n - 1) / digit; // 2.找到n所表示的数字
return Long.toString(num).charAt((n - 1) % digit) - '0'; // 3.
}
}
6,表示数值的字符串
class Solution {
public boolean isNumber(String s) {
if(s == null || s.length() == 0){
return false;
}
//面向测试用例编程,末尾有空格算数字?不解
s = s.trim();
try{
double a = Double.parseDouble(s);
}catch (Exception e){
return false;
}
char c = s.charAt(s.length()-1);
//特,末尾有f,d,D这些不算,但是3.算数字(面向测试用例编程)
return (c >= '0' && c <= '9') || c == '.';
}
}
7,正则表达式匹配
请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。
class Solution {
public:
bool isMatch(string s, string p)
{
if (p.empty()) return s.empty();
bool first_match = !s.empty() && (s[0] == p[0] || p[0] == '.');
// *前字符重复>=1次 || *前字符重复0次(不出现)
if (p.size() >= 2 && p[1] == '*')
return (first_match && isMatch(s.substr(1), p)) || isMatch(s, p.substr(2));
// 不是*,剪去已经匹配成功的头部,继续比较
else
return first_match && isMatch(s.substr(1), p.substr(1));
}
};
(5)力扣热点100题
1,找到所有数组中消失的数字(原地哈希法)
给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。
// 原地哈希法
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
int n = nums.length;
for (int num : nums) {
int x = (num - 1) % n;
nums[x] += n;
}
List<Integer> ret = new ArrayList<Integer>();
for (int i = 0; i < n; i++) {
if (nums[i] <= n) {
ret.add(i + 1);
}
}
return ret;
}
}
2,查找数组中重复的数字
双指针–>将数组转换成链表存环问题
//数组转换成链表,转换成判圈找入口
class Solution {
public int findDuplicate(int[] nums) {
int slow=0,fast=0;
slow=nums[slow];
fast=nums[nums[fast]];
while (slow!=fast)
{
slow=nums[slow];
fast=nums[nums[fast]];
}
// 找到了相遇点fast
slow=0;
while (slow!=fast)
{
slow=nums[slow];
fast=nums[fast];
}
return fast;
}
}
3,找零钱问题
//动态规划解决找零钱个数最小
class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1;
int[] dp = new int[amount + 1];
// dp[i]表示找零钱i需要的最小步数
Arrays.fill(dp, max);
dp[0] = 0;
// 从1到amount
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
4,打家劫舍三
后序遍历+dp思想
class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1;
int[] dp = new int[amount + 1];
// dp[i]表示找零钱i需要的最小步数
Arrays.fill(dp, max);
dp[0] = 0;
// 从1到amount
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coins.length; j++) {
if (coins[j] <= i) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
5,最大正方形
class Solution {
public int maximalSquare(char[][] matrix) {
int m=matrix.length,n=matrix[0].length;
int [][]dp=new int[m][n];
// dp[i][j]表示以i,j为右下角最大正方形的边长的长度
int res=0;
//初始化
for(int i=0;i<m;i++)
{
if(matrix[i][0]=='0')
{
dp[i][0]=0;
}
else dp[i][0]=1;
res=Integer.max(res,dp[i][0]);
}
for(int i=0;i<n;i++)
{
if(matrix[0][i]=='0')
{
dp[0][i]=0;
}
else dp[0][i]=1;
res=Integer.max(res,dp[0][i]);
}
for(int i=1;i<m;i++)
{
for(int j=1;j<n;j++)
{
if(matrix[i][j]=='0')
{
dp[i][j]=0;
}
else{
dp[i][j]=Integer.min(dp[i-1][j],dp[i][j-1]);
dp[i][j]=Integer.min(dp[i][j],dp[i-1][j-1]);
dp[i][j]+=1;
}
res=Integer.max(res,dp[i][j]);
}
}
return res*res;
}
}
6,乘积最大的子数组
class Solution {
public int maxProduct(int[] nums) {
int length = nums.length;
int[] maxF = new int[length];
int[] minF = new int[length];
System.arraycopy(nums, 0, maxF, 0, length);
System.arraycopy(nums, 0, minF, 0, length);
for (int i = 1; i < length; ++i) {
maxF[i] = Math.max(maxF[i - 1] * nums[i], Math.max(nums[i], minF[i - 1] * nums[i]));
minF[i] = Math.min(minF[i - 1] * nums[i], Math.min(nums[i], maxF[i - 1] * nums[i]));
}
int ans = maxF[0];
for (int i = 1; i < length; ++i) {
ans = Math.max(ans, maxF[i]);
}
return ans;
}
}