java
语言基础
十年周杰伦百年周树人
驼峰命名法:
骆驼式命名法就是当变量名或函数名是由一个或多个单词连结在一起,而构成的唯一识别字时,第一个单词以小写字母开始;从第二个单词开始以后的每个单词的首字母都采用大写字母,例如:myFirstName、myLastName,这样的变量名看上去就像骆驼峰一样此起彼伏,故得名.
小驼峰法
变量一般用小驼峰法标识。驼峰法的意思是:除第一个单词之外,其他单词首字母大写。譬如 int myStudentCount;
变量myStudentCount第一个单词是全部小写,后面的单词首字母大写。常用于函数名。
大驼峰法
相比小驼峰法,大驼峰法(即帕斯卡命名法)把第一个单词的首字母也大写了。常用于类名,属性,命名空间等。譬如
public class DataBaseUser;
静态变量
全部大写,单词之间用下划线隔开
数据类型:
基本数据类型 :数据直接存在栈上,传递的是值
引用数据类型:指针存在栈上,数据存在堆里,传递的是指针(地址)
引用数据类型:指针存在栈上,数据存在堆里,传递的是指针(地址)
两个不同类型的数值进行运算,结果的类型是高的那个类型
其他类型接字符串会自动变成字符串**
看清楚等号两边的类型是否一致或左边是否高于右边
默认的整数类型都是**int****,如果要声明long要在后面加大写L(不大写不会报错大写是为了人不容易看错). 默认是double,如果要声明float,结尾要加上f
大类型转小类型会出错 -----> 用强制类型转换来解决:
byte a = 1;//实际上1是int类型,但是1在byte范围之类,所以可以赋值
byte a = 128;// 报错,因为超出byte最大值127,
short a = 128; //下面short 要高转低 强转成 byte
byte b = (byte) a;//强转,无报错,但是b打印-128 1000 0000 负0,补码负128;
变量赋值一般操作: 数据类型 变量名 = 变量值;
基本数据类型: 8种 整数 小数 布尔 字符 //
byte : 1字节 -2^7 to 2^7 - 1
short : 2字节 -2^15 to 2^15 - 1
int : 4字节 -2^31 to 2 ^31 -1
long : 8字节 -2^63 to 2^63 -1
float :4字节 ( 默认是double,如果要声明float,结尾要加上f float a = 3.141f; )
double : 8字节 (默认是double)
double : 8字节 (默认是double)boolean: 1字节 只能是true 或者falsechar : 2字节 用单引号,里面只能有一个字符
转义字符
转义字符本质是字符串
\n 这个是换行
\’ 这个是输出 ’
\\ 这个是输出 \
\t 这个是缩进(制表符)
\" 这个是输出 "
输入空格隔开
System.out.println("输入三个数,以空格隔开:");//下面会自动识别空格
a = sc.nextInt();
b = sc.nextInt();
c = sc.nextInt();
随机数生成器
//产生随机数的工具类 Random ran = new Random();
//nextInt() -- 生成[0,1)之间的随机int类型的数,包含0,不包含1
//nextInt(7) -- 里面数字是几,就是要随机几个数,从0开始>>>>[0,7)
逻辑运算符
里面的代码 会返回布尔值 且 会执行里面的语句
与 & : 左边判断且执行,右边判断且执行
或 | : 左边判断且执行,右边判断且执行
非 ! : 取反,true变成false,false变成true
短路与 && : 只要左边是false,右边不判断不执行
短路或 || : 只要左边是true,右边不判断不执行
一元运算符:
自增: a++ 先用再加1 ++a 先加1再用
int a = 10; int b = (a++)+(++a)+a*10; printf(b); //b= 10 + 12+ 12x10 =142
自减: b-- --b 同理
绝大部分 a++ 相当于 a = a + 1; 但是当a比int类型小的时候,a++没事,a = a+1 ;会出错,因为1是int类型,a比int小
**关系运算符 **:返回的是boolean
== 和 != : 比较的是内存的地址
三元(目)运算符
a>b ? a : b;// 判定为真,输出a,判定为假,输出b.此句的意思是a,b两个数里面找个数值大的来输出
switch
switch结束条件只有两个 : 执行到break 或者 执行到最后一行代码
如果一个case里面没有break,执行完这个case后就会直接顺序执行跳到下一行case
当传入的值没有吻合的case的时候,就会执行default里面的语句//可以接受意外的值
defult不是必须的,不加不报错,但是根据阿里规范化都要加上
传入值默认是int,所以int以下的能,int以上的不能,char则是因为和int可以在编码上互转,String1.7以后才支持)
switch结构中允许的表达式类型:*
int,byte,short,char(ASCII),String(JDK1.7),enum(JDK1.5/枚举)*
不允许:*
long,float,double,boolean
for
循环次数确定的时候用for
for的执行顺序: 初始值–>判定结束条件–>循环体–>初始值走向–>判定结束条件–>…
//初始化一定要给数据类型
// < 算次数直接减, <= 算次数减完加一
//初始值,结束条件,初始值走向
for(int i=0;i<n;i++){//此句意思是 i从0开始循环到n-1.循环了 n 次
if(i%2==0){
System.out.println(i);//循环体
i += 1; //判断语句里面可以放一个初始值的走向,不影响程序运行
}
}
嵌套for循环:内层跑完再跑外层 ; 两个初始值变量不能一样,初始变量 i 的生命周期就是这个for的大括号里面
while
循环次数不确定的时候用while
while的执行顺序: 初始值–>判定结束条件–>循环体–>
int i = 10;//**初始值要放在外面**
while(i>0){//结束条件(一直循环的条件)
if(i%2==0){
System.out.println(i);
}
i -= 1;//初始值走向不能放在判断语句里面,否则会影响循环
}
do while
比while多了一个do,先执行了一次再判断
int i = 10;//初始值要写在外面
do{
System.out.println("如果判定是真,这句话会一直打印..");
}while(ture)//判定条件
方法
其实就是函数,一个方法只做一件事
定义格式: 访问修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…){}
public static int add(int num1,int num2){//有return就必须写返回类型,形参看功能决定有无
return num1+num2;//谁调用这个方法,就给谁返回这个值
}
方法过载重载overload
overload过载: (前提要在同一个类中) 参数列表过载: 就是改一下参数列表的数量,或者类型
返回值类型可以不一样,跟访问修饰符无关
public static double add(double num1,double num2,double num3){//返回值类型不同,参数个数不同
return num1+num2+num3;
}
public static int add(){//没有参数
return 10;
}
递归
**本质:自己调用自己>>>>>**一定要有递归出口
几个案例:九九乘法表:定义一个方法,功能是打印前n行的乘法表,然后里面调用这个方法打印前n-1行的乘法表,开始要设一个递归头,就是当n=1的时候,直接打印1x1=1,
public static void TimeTable(n){
if(n==1){//递归出口
print(1x1=1);
}else{
TimeTable(n-1);
for(i=1;i<n+1;i++){
print(....);
}
print();
}
}
foreach
int[] nums = {1,2,3,4,5,6}
//foreach -- 遍历
for(int num:nums){//num是临时定义要来储存nums的元素的
//不会改变数组中的元素
num = num+1;//对临时变量进行操作
System.out.println(num);//只改变打印结果,打印2 3 4 5 6 7
}
System.out.println("--------------");
for(int num:nums){
System.out.println(num);//因为上面没有改变数组,所以打印的是1 2 3 4 5 6
}
}
跟for的区别:for 是可以直接改变数组元素的,foreach不会改变
数组
一维数组
通过下标索引,下标从0开始,是连续的空间,只能储存同一类型的数据
声明数组变量的方式:
1,动态:先声明内存空间长度,后赋值
2,静态:不用分配空间,系统自动分配声明,我们只需要声明并赋值
直接打印数组会打印他的地址,而不是打印他的元素
//动态初始化:先声明空间长度,后赋值
int []a = new int [5];//代表在堆里面要了一个4(int长度)x5(声明的字节数)=20字节的空间,只能存放int类型
a[0] = 2;//赋值 >>>>>如果没有赋值,就会自动赋予默认值!
//静态初始化:声明的同时并赋值
int []a = new a[]{1,2,3,4,5};//没声明长度
int []a = new a[5]{1,2,3,4,5};//同时声明了长度
int []a = {1,2,3,4,5};//简化版
//错误示范
int []a = new a[5];//这句没错,在内存里面开辟了一块新的空间
a[] = {1,2,3,4,5};//这句有问题,静态分配空间不能分开来声明,一定要一句话完成
二维数组
一维数组里面有若干个一维数组:
//动态初始化:里面所有一维数组的长度都一样
int[][] array = new int[2][4];//2是二位数组的长度,代表里面有两个一维数组,4是里面的每个一维数组的长度
//静态初始化:里面的每个数组要在里面手写出来,长度可以不一样
int[][] array = {{1},{1,2},{1,2,3}}
可变参数 int点点点 放在最后面
1.本质上是数组
2.接收的数据都是相同类型
3.在方法的参数列表中必须写在后面在不确定需要传递多少个相同类型的数据到方法中即可使用可变参数接收
//传入确定多个数,返回他们的和
public static int add(double num1,int ...nums){//实质上编译器把 int ...nums 变成一个数组 int[] nums;
//用for each来遍历数组
int sum = 0;
for(int n:nums){//遍历了nums这个数组,循环赋值给n
sum += n;
}
return sum;
}
二分查找
原理:对半开查找>>>>>>>>只有排好序的数组才能用
具体:数组的下标的最大值和最小值的和除以二为中间值,当要查找的数据和中间值下标的元素相同时则是已经找到了,否则改变下标的最大值或者最小值,重新生成中间值,重新进行比较 ,再查不到就继续循环这个过程…如果当下标的最小值大于下标最大值时,说明数组已经遍历完了,而数据并不在这个数组里面.这时可以结束查找了.
//二分法判断数据是否在数组里面
public static boolean IsInArray(int n,int[] array){//传入要判断的目标数据和目标数组
//定义下标
int max = array.length-1;
int min = 0;
int mid;
//循环比较mid的元素和目标数据
do{
mid = (max+min)/2;//mid不断变动
if(n<array[mid]){
max -= 1;
}else if(n>array[mid]){
min += 1;
}
if(min>max){
return false;
}
}while(n != array[mid]);//mid的元素和目标数据相等时结束
//相等就是返回true
return ture;
}
冒泡排序 Bubble Sort
原理:从最左边的那个开始,左边跟右边比较,大的往右走,往右走的再跟右边的比较,大的往右走,如此循环,最后下标n-1的跟n的比完之后,下标n的(最右的那个)就是最大的了.然后下次比下标最大的就变成了n-1了,如此循环,直到最大的下标变成1了,那就全部排完,变成从小到大了.如果要从大到小排序,就小的往右走;
//下标为0开始
int[] array = {5,4,3,2,1};//目标数组
//循环左边跟右边比较
for(int i=0;i<array.length-1;i++){//循环次数:数组长度-1(最左边那个跟右边的全比一遍)
//循环结尾的下标从 长度-1结束到从1结束
for(j=0;j<array.length-i;j++){
if(array[i]>array[j]){//如果左边比右边大,换位置
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
轮次i 每轮 前和后 哪个有范围哪个可以做 j
选择排序 Changesort
找最小(大),把最小(大)值放到最左边,如此找 n-1 次,就把n个数排好了
原理:假设最左边下标的值是最小值, 那么这个最左边的值就轮流跟右边的值作比较,但凡右边有比它小的,记住那个比它小的下标,全部比完之后,看看下标是不是一开始假设是最小的那个下标,如果是,就说明最左边的是最小的,如果不是,说明记住的那个下标的值是最小的,就把那个值跟假设值调换位置;这样一轮下来我们就把最小的值移到最左边去了.重复这个过程. n个数 下标 0 到 n-1
要比n-1轮就是(i) 1 2 … n-1 最小值的数下标就是(i-1) 0 1 2 … n-2 要循环跟假设值比较的下标就是(j = i+1) 1 2 3 …n
所以实现这个排序的算法就是 外层 for i=0 ; i<=n+1;i++ 控制轮次 内层 for j=i+1; j<=n;j++ 控制每轮的比较交换,记录下标,判断下标,交换最小值
面向对象
类和对象
访问修饰符
讨论的对象: 类里面定义的无封装的属性和方法
范围界限:是否本包 / 是否本类 默认同包 私人本类 公开随便 保护子孙
- 默认包default : int a ; >>> a 在本包中,随便调用 >>> dog1.a = 3;
- 私人类private: private int a ; >>> a 只能在本类中被调用 >>> this.a = 10;//可以 dog.a = 10;//报错
- 公开随便public: public int a; >>> a 随便用 >>> com.yesterday.Dog dog01 = new com.yesterday.Dog();
- 保护子孙protected protected int a; >>> a 只能被本包的其他类或者其他包的子孙类调用 >>>
类
类是一种特殊的数据结构,可以用来定义一个对象.类相当于模具或者蓝图,对象就是从模具或者根据蓝图生产出来的实体案例;
Students stu = new Students();
首先new了一块内存,大小就是Students这种结构所占的长度,然后新建 stu 对象,就是 把 stu 指针指向 Students,然后调用Students的构造方法,执行构造方法. 这个过程就new了一个 Students类的对象出来了
public class Students{
//类属性
private String name;//三个属性都是private,所以外部不能访问,只能通过封装法方法给的接口来操作
private int age;
private String sex;
//构造方法
public Students(){
this(String name);//调用了第三个构造方法,this()函数一定要写在第一行
}//如果自己重写了构造方法,一定要补上无参的,不然报错
//有参构造方法
public Students(String name,int age){//这句传入了age,但是上下的代码中都没调用到,所以age没起作用
this();//调用了无参构造方法
this.name = name;//
print(this.name);
}//可以写多个构造方法,参数数量也不限
public Students(String name){
this.name = name;//修改了类属性name
}
//类方法
public void run(){
print(this.name+"在运动..");
}
}
new对象过程
new一个对象的过程: Cat cat = new Cat(“小黄”);
对象cat --> 类Cat : public Cat(String name){ super(name); } – > 父类Animal : Animal(String name){…}
首先要定义一个cat对象,就要引用Cat类,第一步指向Cat类的有参构造方法,而要创建Cat类就要引用他的父类Animal(Cat有参构造方法调用 super(String name)) ,所以下一步就指向了Animal类的有参构造方法,传参完毕,Animal类构造好了,返回给Cat类,所以Cat类也构造好了,返回给cat,最后cat对象也就new好了.
封装Package
- 将类的某些信息隐藏在类的内部,不允许外部程序进行直接的访问调用。
- 通过该类提供的方法来实现对隐藏信息的操作和访问。
- 隐藏对象的信息。
- 留出访问的对外接口。
- 一些约定俗成的封装方法:
get() :取值
set() :赋值
toString() :return类对象属性(写了这个方法的话,打印对象名就会打印return的东西)
继承inheritance
子类继承父类的 属性 方法 >>>>> 父类的构造方法不能继承
方法推翻重写override:
override :推翻重写! >>>>重写的是方法里面执行的内容,不是方法名字(除了方法主体其他必须一致,访问修饰符不能比父类范围更小)
static静态
一般的属性和方法是属于对象的,静态的是属于类的 >>> 静态的东西全都优先于类对象进入内存
静态属性和方法都可以用类和对象调用,但不可以用this和super调用,因为他们先于对象进入内存
静态属性 static int age; >>>
静态方法 public static void run(){…} >>>
静态代码块 static{…} >>> 在所在类被调用之前会执行一次,以后再也不会执行
抽象类abstract class
我描述:要来当类的模板,定义时多了个abstract,然后里面多了抽象方法,其他都跟其他类一样用法
抽象方法:只有函数名没有函数主体
抽象类:但凡有抽象方法(也可以没有抽象方法,但是如果没有抽象方法,这个抽象类就多余了)抽象类的子类要重写全部的抽象方法,如果只重写了一部分,那么他还是抽象类
public abstract class Animal{
//属性跟非抽象类一样写法
String name;
int age;
//构造方法跟非抽象类一样写法
public Animal(){
}
//反正所有子类都需要重写的方法就用抽象方法
public abstract void run();
//抽象方法肯定是不能private的,因为要给子类继承到
public abstract void eat();
//所有子类都不需要重写的方法
public void sleep(){
print(this.name+" is sleeping")
}
}
抽象类写完了,不能new对象,因为这是规定的,虚拟机看到abstract就不能给你new对象
抽象类的子类实例化的时候,会调用抽象类的构造方法,调用里面的代码块(先于构造方法)
多态Polymorphism
- 多态存在的三个必要条件
- 继承父类
- 重写方法
- 父类引用指向子类
多态: 父类引用指向子类的对象 接口引用指向实现类的对象
用法:1 把父类对象当参数传入 2 把父类对象当返回值返回
向上转型>>装箱
Dog dog = new Dog(); //可以调用Dog类的所有方法
Animal dog1 = new Dog(); //只可以可以调用Animal类的公开方法(有重写就调用重写的)
IRun dog2 = new Dog(); //只可以调用IRun接口的方法
ISwim dog3 = new Dog(); //只可以调用ISwim接口的方法
向下转型>>拆箱
//上面用多态创建了多个dog,只能调用创建时的类或接口的方法,现在拆箱
Dog a1 = (Dog)dog1;
Dog a2 = (Dog)dog2;
Dog a3 = (Dog)dog3;
接口Interface
接口里的方法,都被默认修饰为public abstract类型。
接口里的变量,都被默认修饰为public static final类型,即常量。
造接口: 新建Iterface
新建 ---> class ---> Interface
(jdk8的新特性改成可以有 static (不可重写)和 default(可重写) 的普通方法 )
//接口:飞天的功能
public Interface IFly{//
//里面全是抽象方法因为不能有方法body
//没有构造方法因为不能有body,所以接口也不能被实例化
//没有构造代码块因为不能有body
//接口意义:飞天
void fly();//是个抽象方法
//这个方法可以以乱来的重写,但是函数名起的只是一个规范作用
}
只有接口可以继承接口,一个接口可以继承多个接口
//同时继承了飞和游泳的接口
public IFlyAndSwim extends Ifly,Iswim{
}
用接口:类名后接implements
public class Birds extends Animals implements IFlyAndSwim{
//alt Enter idea帮我把要重写的方法全部列出来了
public void run(){//继承的要重写的抽象方法
pirnt(name+"is running");
}
public void fly(){//实现接口的要重写的抽象方法
print(name+" is flying")
}
public void swim(){//实现接口的要重写的抽象方法
ptint(name+" is swimming")
}
}
接口的多态
//鸟用了飞行接口,鱼也用了飞行接口
IFly bird1 = new Bird();//用接口类名来new这个对象
IFly fish1 = new Fish();
//展现两个对象的接口方法
bird1.fly();
fish1.fly();
//输出结果
小鸟在扑动翅膀
鱼在用火箭飞翔
非接口的多态: 传入不同的用动物类(父类)来new的各个动物(子类对象),展现他们每个动物的吃饭状态
接口的多态: 传入不同的用IFly(接口名)类new的各个动物(用了这个接口的类)对象,展现他们每个动物的用接口实现的扩充技能
public class Man {
//传入不同动物类,展现吃的方法
public void feed(Animals animals){
animals.eat();
}
//传入不同动物类,展现飞的特别技能
public void fly(IFly animals){
animals.fly();//用了这个fly接口的动物
}
}
内存
对象内存
函数里定义的基本数据类型,是直接赋值改变,没用到指针,要到函数出栈才free,在函数里面对外面传进来的变量进行修改时,如果传进来的东西不带指针,那在函数里操作完,传进来的变量也不会有改变.
数组内存
基本类型数组创建的时候,里面的元素都是有实体的数值,所以这时访问不会有问题.
int[] a = new int[5];
char[] a1 = new char[5];
boolean[] a2 = new boolean[3];
System.out.println(a[0]);
System.out.println(a1[0]);
System.out.println(a2[0]);
引用类型的数组创建的时候,里面的元素值都是空指针,这时如果访问这个数组的元素就会报空指针异常.
Father[] father = new Father[10];//没有对引用类型数组进行初始化
System.out.println(father[0]);//这句没问题,打印 father[0] 的地址
System.out.println(father[0].toString());//报错
/*尝试对数组存放的对象进行操作报空指针异常: (因为 null.toString() 不存在)
Exception in thread "main" java.lang.NullPointerException*/
static静态
随字节码文件进入内存 先于类执行
修饰类: 静态类 --> 一般不会有静态类,静态类都是内部静态类
修饰变量: 静态变量 --> 一般写在类里面,用作全局变量
修饰方法: 静态方法 --> 一般放在工具类里面
final最终
修饰:最终类
修饰变量:常量方法
修饰方法:最终方法
内部类
内部类创建对象:1.可以在外部类用方法来实例化 2.可以先创外部类对象再对象.new内部类 3.导内部类的包,new外部类.new内部类 (一般用的都是不用新建对象的方式去创建内部类对象)
内部类:
import com.wu.Outer.Inner;//导包
Inner inner = new Ouuter().newInner;//实例化内部类对象
inner.testInner();//调用内部类方法
内部静态类:
import com.wu.Outer.StaticInner;
Inner inner2 = new Outer.Inner();
局部内部类: 方法里面不能有方法,所以就在方法里面创建一个类,类里面放一个方法,变相变成方法里面调用方法.不过这个类一定要在方法里面实例化和调用,不然在外面有方法调用.
public class Outer{
public void fun1(){
class Inner{
public void fun1(){
System.out.println("局部内部类..")
}
}
Inner inner = new Inner();//要先实例化了
inner.fun1();//还要先调用了
}
}
Outer.fun1();//输出 局部内部类
内部匿名类:一次过实例化一个抽象类的对象(神操),而不用特地去新建一个子类
public class Animals{
public void eat(){
System.out.println("动物吃东西");
}
}
Animals dog = new Animals(){
@Override
public void eat(){
System.out.println("狗吃屎");
}
}
public Interface IEat{
void eat();
}
eat(new IEat(){//用接口new一条鱼
@Override
public void eat(){
println("大鱼吃小鱼..");
}
});
public void eat(IEat animal){
animal.eat();
}
获得时间
System.currentTimeMillis();
异常
测试的时候类名别用Exception,不然会提示后面Exception不兼容的类型
抛出异常:
捕获异常:
try{
//可能出现异常的代码块
int a = 3/0;
}catch(Exception e){
//捕获到的异常的处理方式
printStackTrace();
System.out.println(e.getMessage());
}finally{
//这里的代码是一定会执行的
System.out.println("finally代码..");
}
泛型:
//约束传入容器的类型
ArrayList<Integer> list1 = new ArrayList<Integer>();
TreeSet<E> //E是我们规定想放的数据进TreeSet容器里储存的数据类型(其实就是类名)
TreeSet<Student> = new TreeSet<Student>();//这里Student要实现了Comparable接口. 上面的E 就是Student
TreeSet(Collection<? extends E> c)//这句的意思是把某个Collection旗下的容器传进一个new TreeSet里面,进行自然排序..传进去的这个容器类型只能是 继承于 E (即Student)类的类型