第一部分
Java程序的运行机制
Java语言类型为编译型和解释型的结合。Java首先利用文本编辑器编写Java源程序,源文件的后缀名为.java;再利用编译器(javac)将源程序编译成字节码文件,字节码文件的后缀名为.class;最后利用虚拟机(解释器,java)解释执行
JVM、JRE、JDK
JVM(Java Virtual Machine)是一个虚拟的用于执行bytecode字节码的“虚拟计算机”。他也定义指令集,寄存器集,结构栈,垃圾收集堆,内存区域。JVM负责将Java字节码解释运行,边解释边运行。
JRE(Java Runtime Environment)包含LJava虚拟机,库函数,运行Java应用程序必须的文件。
JDK(Java Development Kit)包含:包含JRE,以及增加编译器和调试器等用于程序开发的文件。
使用命令操作:
第一个Java程序的总结和提升
- Java对大小写敏感,如果出现了大小写拼音错误,程序无法运行
- 关键字public被称为访问修饰符(access modifier),用于控制程序的其他部分对这段代码的访问级别
- 关键字class的意思是类,Java是面向对象的语言,所有代码必须位于类里面
- 一个源文件中至多只能声明一个public的类,其他类的个数不限,如果源文件中包含一个public类,源文件名必须和其定义的public的类名相同。
- 一个源文件可以包含多个class
- main方法是Java应用程序的入口方法,它有固定的书写格式:
public static void main(String[] args){}
变量(variable)
Java是一种强类型语言,每个变量必须声明其数据类型
局部变量:定义在方法或语句块内部。从属于方法/语句块。从声明位置开始到方法或语句块执行完毕,局部变量消失。
基本数据类型: int(整数型,4字节),double(浮点类型8字节),float(浮点类型4字节),bool(布尔型),byte(整数型1字节),short(整数型2字节),long(整数型8字节),char(字符型)
1字节(byte)=8比特(bite)
string强转为int---->Integer.parseInt(salary)
变量的分类
转义字符
算术运算符
算术运算符中:+,-,*,/,%。属于二元运算符,二元运算符指的是需要两个操作数才能完成运算的运算符。
运算规则:
整数运算:
- 如果两个操作数有一个为long,则结果也为long(定义格式long a=6455L)
- 没有long时,结果为int,即使操作数全为short,byte。结果也是int。
浮点运算:
- 如果两个操作数有一个为double,则结果为double。
- 只有两个操作数都是float,则结果才为float。(定义格式flaot a=3.01f;)
赋值扩展运算符
a*=b+3----->a=a*(b+3)
逻辑运算符
逻辑与& | 两个操作数都为True,结果则为true |
逻辑或 | 两个操作数有一个true则结果为true |
短路与&& | 只要有一个false则结果为false |
短路或 | 只要 有一个true则结果为true |
短路非! | 取反操作 |
逻辑异或^ | 相同为false,不同为true |
其中短路与&&的意思是两个数前面一个为false则不对后面的操作数处理,即使后面的的操作数会报错
短路或||则是第一个为true则结果为true,同上。
位运算符
位运算指的是进行二进制的运算
取反~ | 即0变1,1变0 |
按位与& | 两个二进制数进行运算时两个二进制数都为1时结果为1,其他都为0 |
按位或 | 两个二进制数运算两个二进制其中有一个二进制为1结果都为1,其余为0 |
按位异或 ^ | 两个二进制数相同为false,不同为true |
左移运算符<< | 左移一位相当于乘2 |
右移运算符>> | 右移一位相当于除2取商 |
位运算结合逻辑运算就很好理解了,二进制1位true,0为false。
左移运算符给个例子就好懂了:a=5<<2,则a=20,522。a=5<<1,结果为10。a=5<<3,结果为40.
右移运算符:a=5>>1;5/2=2结果a=2。b=5>>2,5/4=1结果b为1。c=10>>3,结果c=1。
字符串连接符
“+”运算符两侧中只要有一个时字符串类型,系统自动将另一个操作数转换为字符串类型进行连接(针对字符串)
public class Test{
public static void main(Sting[] args){
int a=5;
String b="3";
System.out.println(a+b); //输出结果为53,类型为字符串类型
}
}
条件运算符
x?y:z
三目条件运算符:意思就是根据?前的x判断,当x的值为true返回y,x值为false返回z
运算符优先级
关系运算符比逻辑运算符优先。
键盘的输入与输出
System.out.println();
输出结果是自动换行的
System.out.print();
输出的结果是不自动换行的
import java.util.Scanner;
public calss TestScanner{
public static void main(String[] args){
Scanner s = new Scanner(System.in);
String nume = s.nextLine();
System.out.println(""+nume);
int age = s.nextInt();
double salary = s.nextDouble();
}
}
第二部分
桌游小游戏项目
//用的Jfarm插件
package com.bjsxt;
import java.awt.*;
import javax.swing.*;
public class BallGame extends JFrame{
Image ball = Toolkit.getDefaultToolkit().getImage("images/ball.png");
Image desk = Toolkit.getDefaultToolkit().getImage("images/desk.png");
double x=200;
double y=200;
double degree=3.14/3;
/* int x=200;
int y=200;
boolean right=true;*/
//绘制窗口
public void paint(Graphics g){
System.out.println("窗口被画了一次");
g.drawImage(desk,0,0,null);
g.drawImage(ball,(int)x,(int)y,null);
/* if (right)
x=x+10;
}else {
x=x-10;
}
if(x>450) {
right = false;
}
if(x<40){
right=true;
}*/
x=x+10*Math.cos(degree);
y=y+10*Math.sin(degree);
if(y>501||y<0){
degree=-degree;
}
if(x>856||x<0){
degree=3.14-degree;
}
}
//创建窗口
void launchFrame(){
setSize(856,501);
setLocation(100,100);
setVisible(true);
//实现动画,每秒绘制窗口25次
while (true) {
repaint();
try {
Thread.sleep(40); //is = 1000ms;
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public static void main(String[] args){
System.out.println("我的小游戏开始了!");
BallGame game = new BallGame();
game.launchFrame();
}
}
这个跟着敲一遍就可
第三部分控制语句
这句话挺重要的:任何软件和程序,小到练习,大到一个操作系统,本质上都是由"变量,选择语句,循环语句"组成。
Math.random()语法生成的数类型为double
条件判断语句if
if单分支结构
if-else双分支结构
if-else if -else多分支结构
switch语句
switch语句会根据表达式的值从相匹配的case标签处开始执行,一直执行到break,如果没有break,则执行下一个case,或者是switch语句的末尾,如果表达式的值与任一case值不匹配则进入到default。
switch语句中case标签在JDK1.5之前必须是整数(long除外)或者枚举,不能是字符串,JDK1.7之后允许使用字符串。
package cn.itbaizhan;
import java.util.Scanner;
public class TestSwitch {
public static void main(String[] args){
System.out.println("请输入一个数");
Scanner s = new Scanner(System.in);
int grade = s.nextInt();
switch(grade){
case 1:
System.out.println("大学一年级");
break;
case 2:
System.out.println("大学二年级");
break;
case 3:
System.out.println("大学三年级");
break;
default:
System.out.println("其他");
}
}
}
循环结构(while)
记住格式和执行流程
public class TestWhile {
public static void main(String[] args){
int a = 1;
while(a<=3){
System.out.println("I LO"+a);
a++;
}
//1+2+3+4+5+.....
int b = 1;
int sum = 0;
while(b<=100){
sum += b;
System.out.println("当前和为:"+sum);
b++;
}
}
}
循环结构(for)
记住格式for(i;i<n;i++)
public class TestFor {
public static void main(String[] args){
Scanner s = new Scanner(System.in);
int a = s.nextInt();
for(int i=1;i<=a;i++){
System.out.println("I L"+i);
}
}
}
死循环:for( ; ; ) 等于while(true)
嵌套循环
循环里面套循环,附一个简单的程序
public class workLoop {
public static void main(String[] args){
for(int i=1;i<=5;i++){
for(int j=0;j<=4;j++){
if((i+j)%2==0){
System.out.print("#"+"\t");
}
else{
System.out.print("*"+"\t");
}
}
System.out.println();
}
}
break语句和continue语句
continue语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。说白了就是回到循环的头部进行下一次的循环
continue用在while do-while中,continue语句立刻跳到循环首部,跳过了当前循环的其余部分
continue用在for循环中,跳到for循环的迭代因子部分
break 则是直接跳出循环
附:Math,round()// 四舍五入的语法
把100-150之间不能被3整除的数输出,并且每行输出5个,我首先写的是没用到continue。
// 没用到continue
public class Test_06 {
public static void main(String[] args){
int j = 0;
for(int i=100;i<=150;i++){
if(i%3!=0){
System.out.print(i+"\t");
j++;
if (j%5==0)
System.out.println();
}
}
}
}
//用continue编写
public class Test_06 {
public static void main(String[] args){
int j = 0;
for(int i=100;i<=150;i++){
if(i%3==0){
continue;
}
else{
j++;
System.out.print(i+"\t");
if(j%5==0){
System.out.println();
}
}
}
}
}
带标签的break和continue
就是continue的时候是返回到outer的那个for循环,outer可以随便取名字的
public class Test_07 {
public static void main(String[] args){
outer:for(int i=1;i<=100;i++){
for(int j=2;j<i/2;j++){
if(i%j==0){
continue outer;
}
}
System.out.println(i+" ");
}
}
}
第四部分 -方法
方法就是一段用来完成特定功能的代码片段,类似于其他语言的函数。方法用于定义该类或该类的实例的行为特征和功能实现。
方法的声明格式:
[修饰符1 修饰符2 …] 返回值类型 方法名(形式参数列表){
java语句;
}
public static void 方法名(形参){ // 形参用于方法的定义
}
方法的调用方式:
对象名.方法名(实参列表) // 实参用于调用
方法的重载
方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法,调用时会根据不同的参数自动匹配对应的方法。
重载的方法,实际是完全不同的方法,只是名称相同而已。
构成方法重载的条件:
- 不同的含义:形参类型,形参个数,形参顺序不同
- 只有返回值不同不构成方法的重载
递归
目前只讲到了基础,建议在数据结构重点看。
第五部分面向对象
public class SxStu {
// 属性(成员变量)
int id;
String sname;
int age;
// 方法
void study(){
System.out.println("");
}
// 构造方法(方法名和类名保持一致)
SxStu(){
}
public static void main(String[] args){
SxStu s1 = new SxStu();
System.out.println(s1.id); //0
System.out.println(s1.sname);//null
s1.id = 123;
s1.sname = "zc";
System.out.println(s1.id);//123
System.out.println(s1.sname);//zc
}
}
同一个文件内类之间的调用
public class Test01 {
public static void main(String[] args){
Father.InFatehr();
Son S = new Son();
S.Inson();
}
}
class Son{
public void Inson(){
System.out.println("213");
}
}
class Father{
public static void InFatehr(){
System.out.println("456");
}
}
上面代码可以看出,一个文件内只能有一个public类,在调用其他类的时候,如果调用类的方法用static声明,则直接类型.方法名。如果没用static声明则则要先new一个对象,之后在调用----静态的方法同过类直接调用,非静态方法同过对象去调用(原理我也不懂,先记住。)
构造方法(构造器 constructor)
构造方法的作用:创建对象,凡是必须和new一起使用。对对象进行初始化。也就是构造方法是为对象初始化用的。
- 构造方法通过new关键字调用
- 构造器虽然没有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造方法使用return返回某个值
- 如果自己没有定义构造方法,编译器会自己定义一个无参的构造函数
- 构造方法的方法名必须和类名一致。
构造方法(构造器)重载
跟方法是一样的
public class User{
int id;
String name;
String pwd;
public User(){
}
public User(int id, String name){
this.id = id; //this.id表示属性id,单独id表示形参
this.naem=naem
}
public User(int id,String name, Sting pwd){
this.id = id; //this.id表示属性id,单独id表示形参
this.naem=naem
this.pwd = pwd;
}
public static void main(String[] args){
User u1 = new User();
User u2 = new User(100,"zc");
User u3 = new User(100,"zcc","qwe");
}
}
面向对象2
学习目标
面向对象的内存分析
JAVA虚拟机内存模型概念
程序执行内存分析
java虚拟机内存可以分为是那个区域,虚拟机栈stack、堆、方法区method area。
虚拟机栈(简称栈)的特点如下:
- 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
- JVM为每个线程创建一个栈。用于存放该线程执行方法的信息(实际参数、局部变量等)
- 栈属于线程私有,不能实现线程间的共享
- 栈的存储特性是“现金后出,后进先出”
- 栈是由系统自动分配,速度块!栈式一个连续的内存空间。
堆的特点:
- 堆用于存储创建好的对象和数组(数组也是对象)
- JVM只有一个堆,被所有线程共享
- 堆是一个不连续的内存空间,分配灵活,速度慢!
方法区(又叫静态区,也是堆)
- 方法区是JAVA虚拟机规范,可以有不同的实现
- JVM只有一个方法区,被所有线程共享
- 方法区实际也是堆,只是用于存储类,常量相关的信息
- 用来存放程序中永远是不变或唯一的内容
public class Person{
String name;
int age;
public void show(){
System.out,println(""+naem+""+age);
}
}
public class TestPerson{
public static void main(String[] args){
//创建p1对象
Person p1 = new Person()
p1.age = 24;
p1.name = "zc";
p1.show
//创建p2对象
Person p2 = new Person()
p2.age = 22;
p2.name = "zcc";
p2.show
}
}
this、static关键字
this本质就是创建好的对象的地址,由于在构造方法调用前,对象已经创建,因此,在构造方法中也可以使用this代表当前对象。
this不能用于static方法中
class Demo{
String str = "这是成员变量";
void fun(String str){
System.out.println(str);
System.out.println(this.str);
this.str = str;
System.out.println(this.str);
}
}
public class This{
public static void main(String args[]){
Demo demo = new Demo();
demo.fun("这是局部变量");
}
}
//这是局部变量
//这是成员变量
//这是局部变量
在类中,用static声明的成员变量为静态成员变量,也称为类变量,类变量的声明周期和类相同,在整个应用程序执行期间都有效:
有些东西光听原理和看文字,听不太懂,不如一个程序来的直接。
- static方法中不可以直接访问非static的成员。
public class User {
int id;
static String name;
String pwd;
String company = "北京尚学堂";
public User(int id, String name){
this.id = id;
this.name = name;
}
public void login(){
System.out.println("登陆了"+this.name);
}
public static void printCompany(){
System.out.println(name);
}
public static void main(String[] args){
User u1 = new User(231, "zc");
User.printCompany();
//User.company = "背景";
User.printCompany();
}
}
包机制
包机制是java中管理类的重要手段,开发中,会遇到大量同名的类,通过包很容易解决类重名的问题,也可以实现对类的有效管理,包对于类,相当于文件夹对文件的作用。
包名:域名倒着写即可,再加上模块名,便于内部管理。
导入类import
导入静态的属性 import static com.bjsxt,test2.Student.school;(school在下面代码中可以直接用)
面向对象3
1.继承
2.封装
3.多态
4.对象的转型
继承
- 代码复用,更加容易实现类的扩展
- 方便对事物建模
- java中类没有多继承,即只有一个直接父类。接口有多继承。
使用extends。子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如父类私有的属性和方法)
方法的重写override
重写也叫覆盖,就是把父类的方法重新改写在自己这里用。
方法重载需符合下面三个要点
- “==”方法名,形参列表相同
- “<=”返回值类型和声明异常类型,子类小于等于父类
- “>=”访问权限,子类大于等于父类
public class TestDog {
public static void main(String[] args){
Animal a = new Animal();
Animal b= new Dog();
a.move();
b.move();
((Dog) b).bark();
//直接b.brak()是不能运行的
}
}
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
System.out.println("狗可以跑和走");
}
public void bark(){
System.out.println("狗可以叫");
}
}
final关键字
final关键字作用:
- 修饰变量:被final修饰的变量不可改变,一旦付了初值,就不能被重新赋值。
final int a = 20;
2.修饰方法:方法不可被子类重写,但可以被重载
final void study(){}
3.修饰类:修饰的类不能被继承
组合
组合可以方便的代码复用,组合不同于继承,更加灵活,组合的核心就是将父类对象作为子类的属性,然后子类通过调用这个属性获得父类的属性和方法。
public class A {
public static void main(String[] args){
D d = new D();
d.b.shout();
}
}
/*final*/ class B{
public final void shout(){
System.out.println("ss");
}
}
class C extends B{
public void shout(int a){
}
}
class D {
B b = new B();
}
Object类
Object类是所有java类的根基类,也就意味着所有的java对象拥有Object类的属性和方法,如果在类的声明中未使用extends关键字指明其父类,则默认继承Object类。
==和equals
看这里,这个解释蛮清楚的 equals重写:alt+insert用于重写get、set、equals等。equal是用来判断值是否相等的。
super关键字
在一个类中,若是构造方法的第一行代码没有显示的调用super()或者this(),那么java默认都会调用super()。含义是调用父类的无参构造方法—如下代码
public class Testsuper {
public static void main(String[] args){
System.out.println("开始创建一个child类对象.....");
new childclass();
}
}
class fatherclass{
public fatherclass(){
System.out.println("创建父类");
}
}
class childclass extends fatherclass{
public childclass(){
System.out.println("创建子类");
}
}
结果为:
开始创建一个child类对象.....
创建父类
创建子类
封装
注:关于protected
1.若父类和子类在同一个包中,子类可访问父类的protected成员,也可访问父类对象的protected成员
2.若子类和父类不在同一个包中,子类可以访问父类的protected成员,不能访问父类对象的protected成员(即可以super()调用父类的成员,不可以new一个对象来调用)
封装的使用细节
开发中封装的简单规则;
属性一般使用private访问权限–属性私有后,提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注:boolean变量的get方法是is开头)
方法:一些只用于本类的辅助方法可以用private修饰,希望其他类调用的方法用public修饰。
public class Person2 {
private String name;
private int age;
private boolean flage;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public boolean isFlage(){
return flage;
}
public void setFlage(boolean flage){
this.flage = flage;
}
}
public class Test2 {
public static void main(String[] args){
Person2 p2 = new Person2();
p2.setAge(25);
System.out.println(p2.getAge());
}
}
instanceof
instanceof通过返回一个布尔值来指出,某个对象是否是某个特定类或者是该特定类的子类的一个实例。
多态
多态概念和实现
多态值的是同一个方法调用,由于对象不同可能会有不同的行为,现实生活中,同一个方法,具体实现会完全不同。
多态的要点:
1.多态是方法的多态,不是属性的多态。
2.多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
3.父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
方便的方法的调用
public class Animal {
public void shout() {
System.out.println("叫了一声");
}
}
class Dog extends Animal{
@Override
public void shout(){
System.out.println("汪汪汪");
}
}
class Cat extends Animal{
@Override
public void shout(){
System.out.println("喵喵喵");
}
}
class Mouse extends Animal{
@Override
public void shout(){
System.out.println("zizizi");
}
}
public class TestPolym {
static void animalCry(Animal a){
a.shout();
}
public static void main(String[] args){
Dog d = new Dog();
animalCry(d);
animalCry(new Cat());
animalCry(new Mouse());
}
}
对象的转型
程序三步:1、编译。2、运行
Animal a = new Dog(); //向上类型转换,自动的
Dog d2 = (Dog) a; //强制类型转换,向下类型转换
d2.seeDoor();
// Cat c3 = (Cat) a;
//c3.catchMouse();
if(a instanceof Dog){
Dog d3 = (Dog) a;
d3.seeDoor();
}
else if(a instanceof Cat){
Cat c4 = (Cat) a;
c4.catchMouse();
}
抽象方法和抽象类
抽象方法
使用abstract修饰方法,没有方法体,只有声明,定义的是一种规范,就是告诉子类必须要给抽象方法提供具体的实现。(没有具体的实现)
抽象类
包含抽象方法的类就是抽象类,通过abstract方法定义规范,然后要求子类必须定义具体实现,通过抽象类,我们就可以做到严格限制子类的设计,便于子类之间更加通用。
抽象类的使用要点:
- 有抽象方法的类只能定义成抽象类
- 抽象类不能实例化,即不能用new来实例化抽象类
- 抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用来被子类调用。
- 抽象类只能用来被继承
- 抽象方法必须被子类实现
abstract class Animal{
abstract public void shout();//抽象方法
}
class Dog extends Animal{
public void shout(){//必须实现父类的抽象方法,否则报错
System.out.println("zxc");
}
public void seeDog(){
System.out.println("看门");
}
}
//测试抽象类
public class TestAbstract {
public static void main(String[] args){
Dog a = new Dog();
a.shout();
a.seeDog();
}
}
接口
接口链接 普通类:具体实现
抽象类:具体实现,规范(抽象方法)
接口:规范!
定义和使用接口
public interface Volant {
/*public static final*/ int MAX = 100;
void fly();
void stop();
}
interface Honest{
void helpother();
}
public class superman implements Volant,Honest{
@Override
public void fly(){
System.out.println("横着飞");
}
@Override
public void stop(){
System.out.println("竖着飞");
}
@Override
public void helpother() {
System.out.println("飞哪里");
}
public static void main(String[] args){
Volant m1 = new superman();
m1.fly();
m1.stop();
Honest m2 = (Honest) m1; //强转之后调用的方法是看new的对象里有没有这个方法
m2.helpother();
}
}
接口多继承
字符串String类详解
String时开发过程中最常用的类。我们不仅要掌握String类常见的方法,对于String的底层实现也要掌握好。
- String类又称作不可变字符序列
- String位于java.lang包中,java程序默认导入java.lang包下的所有类
- java字符串就是Unicode字符序列。
- java没有内置的字符串类型,而是在标准java类库中提供一个预定义的类string,每个双引号括起来的字符串都是String类的一个实例
内部类
内部类:提供了更好的封装,只能让外部类直接访问,不允许同一个包中的其他类直接访问,可以直接访问外部类的私有属性,内部类被当成其他外部类的成员,但外部类不能访问内部类的内部属性
非静态内部类
- 非静态内部类对象必须寄存在一个外部类对象里
- 非静态内部类可以直接访问外部类的成员
- 非静态内部类不能有静态方法,静态属性和静态初始化块
- 成员变量访问要点:
代码中
package com.testInner;
public class outer1 {
private int age = 10;
private void show(){
System.out.println("outer1.show");
}
public class Inner1{
private String name = "tom";
private int age = 20;
public void showInner(){
System.out.println("Inner1.showInner");
System.out.println(age);
System.out.println(outer1.this.age);//调用外部类的属性
show(); //内部类可以直接使用外部类的成员
}
}
public static void main(String[] args) {
outer1.Inner1 inn01 = new outer1().new Inner1();
inn01.showInner();
outer1 out2 = new outer1();
Inner1 inn02 = out2.new Inner1();
inn02.showInner();
}
}
静态内部类
- 静态内部类可以访问外部类的静态成员,不能访问外部类的普通成员
- 静态内部类看作外部类的一个静态成员
class outer2{
private int a = 10;
private static int b= 20;
static class Inner2{
public void test(){
// System.out.println(a); //金泰内部类不能访问外部类的普通属性
System.out.println(b); //静态内部类可以访问外部类的静态属性
}
}
}
public class TestStaticInnerClass {
public static void main(String[] args) {
outer2.Inner2 inner = new outer2.Inner2();
inner.test();
}
}
数组
数组定义:数组是相同类型数据的有序集合,数组描述的是相同类型的若干个数据,按照一定的先后次序组合而成,每一个数据称作一个元素,每个元素可以通过一个索引来访问它们。
- 长度是确定的,数组一旦被创建,它的大小就是不可以改变的
- 其元素的类型必须是相同的,不允许出现混合类型
- 数组类型可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组也是对象,数组的元素相当于对象的属性。
数组声明
type[] arr_name;
type arr_name[];
声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM才分配空间,这是才与长度有关
声明数组时并没有真正的数组被创建
构造一个数组,必须指定长度
数组初始化三种方式
package com.array;
public class homework1 {
public static void main(String[] args) {
//静态初始化
String[] grads = new String[]{"java得分60","python得分70","大数据80"};
for(int i=0;i<grads.length;i++){ System.out.println(grads[i]);
}
//静态初始化
int[] intArr;
intArr = new int[]{1,2,5};
for(int i=0;i<intArr.length;i++){
System.out.println(intArr[i]);
}
//动态初始化
String[] grad = new String[3];
grad[0] = "sd";
grad[1] = "gc";
grad[2] = "cc";
for(int i=0;i<grad.length;i++){ System.out.println(grad[i]);
}
}
}
数组拷贝
System.arraycopy(sobject src,int srcpos,object dest,int destpos,intlength),该方法可以将src数组里的元素赋值给dest数组的元素,其中srcpos指定从src数组的第几个元素开始赋值,length参数指定src数组的多少个元素赋给dest数组的元素。
数组排序
Arrays.sort();
数组的输出:System.out.println(Arrays.toString(a));
多维数组
public class Test04 {
public static void main(String[] args) {
int[][] a = {{1,2,3},{3,4},{3,5,6,7}};
System.out.println(a[2][3]);
int[][] a1 = new int[3][4];
//动态初始化
int[][] a1 = new int[3][];
a1[0] = new int[]{1,2};
a1[1] = new int[]{2,2};
a1[2] = new int[]{2,2,3,4};
System.out.println(a1[1][1]);
}
}
package com.array;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
/*
*使用javabean和数组存储表格的信息
*/
public class homework2 {
public static void main(String[] args) {
Home home1 = new Home(1,"百战","BZ",99.21,0.9);
Home home2 = new Home(2,"键盘","WO",403.00,0.7);
Home home3 = new Home(3,"实战","BK",89.00,0.8);
Home home4 = new Home(4,"高其","GQ",700.00,0.5);
Home home5 = new Home(5,"大米","DM",900.00,0.3);
//Home[] homes = {home1,home2,home3,home4,home5};
Home[] homes = new Home[5];
homes[0] = home1;
homes[1] = home2;
homes[2] = home3;
homes[3] = home4;
homes[4] = home5;
for(int i=0;i<homes.length;i++){ System.out.println(homes[i].getId()+homes[i].getName()+homes[i].getType()+homes[i].getPrice()+homes[i].getDis()+"\t");
}
for(int i=0;i<homes.length;i++){
System.out.println(homes[i]);
}
}
}
class Home{
private int id;
private String name;
private String type;
private double price;
private double dis;
public Home(){}
public Home(int id, String name, String type, double price, double dis) {
this.id = id;
this.name = name;
this.type = type;
this.price = price;
this.dis = dis;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getDis() {
return dis;
}
public void setDis(double dis) {
this.dis = dis;
}
@Override
public String toString() {
return getId()+getName()+getType()+getPrice()+getDis();
}
}
常用类
基本数据类型不是对象
Number类是抽象类,因此它的抽象方法,所有子类都需要提供实现,Number类提供了抽象方法,intValue().longValue().floatValue.doubleValue(),意味着所有的数字型包装类都可以相互转换。
Number类和数字包装类是父子关系,Number类是抽象类
包装类的两个作用:1基本数据类型转化为类对象,2数据类型之间的转换比,如String和int之间的转换可以通过int的包装类Integer来实现。
Integer类缓存处理的范围-128~127
自动装箱和拆箱
package com.bjsxt.test1;
public class TestWraperClass {
public static void main(String[] args) {
//基本数据类型转为对象
Integer i = new Integer(300);
Integer i2 = Integer.valueOf(30);
//包装类对象转换为基本数据类型
double d = i2.doubleValue();
//将字符串数字转成包装类对象
Integer i3 = Integer.valueOf("123");
Integer i4 = Integer.parseInt("334");
//将包装类对象转换成字符串
String str = i3.toString();
//一些常用的常量
System.out.println(Integer.MAX_VALUE);
//自动装箱
Integer a = 300; //编译器帮你改成:Integer a = Integer.valueOf(300);
//自动拆箱
int b = a; //编译器帮你改成:a.intValue();
//Integer c = null;
//int c2 = c; //报错,空对象调不了方法
//包装类缓存问题
Integer d1 = 4000;
Integer d2 = 4000;
//当数字[-128,127]之间的时候,返回缓存数组中的某个元素
Integer d3 = 123;
Integer d4 = 123; //Integer.valueof(123)
System.out.println(d1==d2);//两个不同的对象,false
System.out.println(d1.equals(d2)); //比较的是值true
System.out.println(d3==d4); // true
//将string类型通过包装类转换成int类型
int a1 = new Integer("123");
}
}
字符串相关类
String类、StringBuilder类、StringBuffer类是三个字符串相关类。
String字符串内容全部存储到value[]数组中,而变量value是final类型的,也就是常量(即只能被赋值一次),这就是“不可变对象”的典型定义方法,String方法中的substring()是对字符串的截取操作,本质上是生成了新的字符串
package com.bjsxt.test1;
public class TestString {
public static void main(String[] args) {
//编译器做了优化直接在编译的时候将字符串进行拼接
String str1 = "hello" + "java"; //相当于str1="hellojava"
String str2 = "hellojava";
System.out.println(str1==str2);//true
String str3 = "hello";
String str4 = "java";
//编译的时候不知道变量中存储的是什么所以没办法在编译的时候优化
String str5 = str3 + str4;
System.out.println(str2==str5); //false
}
}
StringBuffer JDK1.0版本提供的类,线程安全,做线程同步检查,效率低。
StringBuilder JDK1.5版本提供的类,线程不安全,不做线程同步检查,因此效率高。建议采用此类
//操作
package com.bjsxt.test1;
public class TestString2 {
public static void main(String[] args) {
String str = "aabb"; //不可变字符序列
StringBuilder sb = null; // 可变字符序列
StringBuffer sb2 = null; //可变字符序列
sb = new StringBuilder("gao");
sb.append(123);
sb.append(456);
System.out.println(sb);
sb.append("aa").append("bb").append("cc"); //源码return this
System.out.println(sb);
for(int i=0;i<10;i++){
sb.append(i);
}
System.out.println(sb);
StringBuffer sb1 = new StringBuffer("ad");
sb1.insert(0,"s").insert(0,"z");
System.out.println(sb1);
sb1.delete(0,1); //删除0-1字符串
System.out.println(sb1);
sb1.deleteCharAt(0).deleteCharAt(0); //删除其中某个元素
System.out.println(sb1);
}
}
字符串可变序列与不可变序列的效率
package com.bjsxt.test1;
public class Test {
public static void main(String[] args) {
/*使用String进行字符串的拼接*/
String str8 = "";
//本质上StringBuilder拼接,但是每次循环都会生成一个StringBuilder对象
long num1 = Runtime.getRuntime().freeMemory();//获取系统剩余内存空间
long time1 = System.currentTimeMillis();//获取系统的当前时间
for(int i=0;i<5000;i++){
str8 = str8 + i;//相当于产生5000个对象
}
long num2 = Runtime.getRuntime().freeMemory();
long time2 = System.currentTimeMillis();
System.out.println("string占用内存:"+(num1 - num2));
System.out.println("string占用时间"+(time2 - time1));
/*使用Stringbuilder进行字符串的拼接*/
StringBuilder sb1 = new StringBuilder("");
long num3 = Runtime.getRuntime().freeMemory();
long time3 = System.currentTimeMillis();
for(int i=0;i<5000;i++){
sb1.append(i);
}
long num4 = Runtime.getRuntime().freeMemory();
long time4 = System.currentTimeMillis();
System.out.println("StringBuilder占用内存" + (num3 - num4));
System.out.println("StringBuilder占用时间" + (time4 - time3));
}
}
Date类用法
import java.util.Date;
public class Testdata {
public static void main(String[] args) {
long a = Long.MAX_VALUE/(1000L*3600*24*365);
System.out.println(a);
long nowNum = System.currentTimeMillis(); //代表当前时刻的毫秒数
System.out.println(nowNum);
Date d1 = new Date(); //如果不传参,则表示是当前时间
System.out.println(d1);
System.out.println(d1.getTime()); //输出对应的毫秒数
Date d2 = new Date(1000L*3600*24*365*250);
System.out.println(d2);
}
}
DateFormat时间格式化
DateFormat类的作用:
把时间对象转换成指定格式的字符串。反之,把指定格式的字符串转化为时间对象
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TestDateFormat {
public static void main(String[] args) throws ParseException {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
//将字符串转成Date对象
Date d1 = df.parse("1971-3-10 10:40:20");
System.out.println(((Date) d1).getTime());
//将Date对象转为字符串
Date d2 = new Date(1000L*3600*23);
String str = df.format(d2);
System.out.println(str);
SimpleDateFormat df1 = new SimpleDateFormat("yyyy年MM月dd日 hh时mm分ss秒");
//将字符串转成Date对象
Date d3 = df1.parse("1971年3月10日 10时40分20秒");
System.out.println(((Date) d3).getTime());
//将Date对象转为字符串
Date d4 = new Date(1000L*3600*23);
String str2 = df1.format(d4);
System.out.println(str2);
}
}
知道有什么就可以了。有用到在搜
Calendar日历类
Calendar类是一个抽象类,为我们提供了关于如期计算的相关功能,比如年、月、日、时、分、秒的展示和计算。
GregorianCalendar是Calendar的一个具体子类,提供标准的日历系统。
注:一月时0,二月是1…
其他的就自行百度吧
Math类
java.lang.Math提供了一系列静态方法用于科学计算,其方法的参数和返回值类型一般为double型。
import java.lang.Math;
public class TestMath {
public static void main(String[] args) {
System.out.println(Math.ceil(3.2)); //大于3.2的最小整数
System.out.println(Math.floor(3.2)); //小于3.2的最大整数
System.out.println(Math.round(3.2)); //四舍五入
System.out.println(Math.round(3.8));
System.out.println(Math.abs(-45)); //绝对值
System.out.println(Math.sqrt(64)); //平方根
System.out.println(Math.pow(5,2)); //a的b次幂
System.out.println(Math.pow(2,5)); //b的a次幂
System.out.println(Math.PI); //圆周率
System.out.println(Math.E); //e
System.out.println(Math.random()); //[0,1] 随机数
}
}
Random类
可以更好生成随机数,语法自行百度
File类
File类用来代表文件和目录,在开发中,读取文件、生成文件、删除文件、修改文件的属性经常会用到本类
import java.util.Date;
import java.io.File;
import java.io.IOException;
public class TestFile {
public static void main(String[] args) throws IOException {
//创建文件
File f1 = new File("g:/java基础"); //文件路径
System.out.println(System.getProperty("user.dir")); //当前项目的根路径
File f3 = new File(System.getProperty("user.dir"));
f1.createNewFile();
System.out.println("FILe是否存在"+f1.exists());
System.out.println("FILe是否是目录"+f1.isDirectory());
System.out.println("FILe是否是文件"+ f1.isFile());
System.out.println("FILe最后修改时间"+ new Date(f1.lastModified()));
System.out.println("FILe的大小"+f1.length());
System.out.println("FILe的文件名"+f1.getName());
System.out.println("FILe的目录路径"+f1.getPath());
File f4 = new File("G:/movies/大陆/学习/编程/尚学堂");
//创建路径上所有文件夹
f4.mkdirs();
f4.delete(); //删除最后一个文件夹
}
}
枚举
格式:enum 枚举名{
枚举体(常量列表)
}
枚举体就是放置一些常量,我们可以写出我们的第一个枚举类型
enum Season{
SPRING,SUMMER,AUTUMN,WINDER
}
所有的枚举类型隐性地继承自java.lang.Enum。枚举实质上还是类!而每个被枚举的成员实质上就是一个枚举类型的实例,他们默认都是public static final 修饰的。可以通过枚举类型名使用他们。
建议:当你需要定义一组常量时,可以使用枚举类型
尽量不要使用枚举的高级特性,会使用简单的即可
//枚举的循环与定义
import java.util.Random;
public class TestEnum {
public static void main(String[] args) {
System.out.println(Season.SPRING); //打印出的时SOPRING
//枚举遍历,增强for循环
for(Week k:Week.values()){
System.out.println(k);
}
Week[] ws = Week.values();
System.out.println(ws[1]);
int a = new Random().nextInt(4);//随机生成0,1,2,3的随机数
switch (Season.values()[a]){
case SPRING:
System.out.println("春天");
break;
case AUTUMN:
System.out.println("秋天");
break;
case SUMMER:
System.out.println("夏天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
}
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
enum Week{
星期一,星期二,星期三,星期四,星期五,星期六,星期日
}
递归
算法时细学
异常
try{
}
catch(Exception e){
}
异常机制本质:当前程序出现错误,程序安全的,继续执行机制。
异常(Exception)的概念
异常指程序运行过程中出现的非正常现象,例如用户输入错误、除数为0、需要处理文件不存在,数组下标越界
在Java的异常处理机制中,引进了很多用来描述和处理异常的类,称为异常类,异常类的定义中包含了该类异常的信息和对异常进行处理的方法。
Exception类是所有异常类的父类,其子类对应各种各样可能出现的异常事件。通常JAVA的异常可分为:
RuntimeException 运行时异常
CheckedException 已检查异常
import java.io.File;
public class Test01 {
public static void main(String[] args) {
try{
int i = 1/0;
}catch (Exception e){
e.printStackTrace(); //RuntimeException打印出异常信息,这是运行时的异常
}
File f = new File("D:/a.txt");
try{
f.createNewFile();
}catch (Exception e){
e.printStackTrace(); //CheckedException这是编译时的异常
}
}
}
异常处理方式一捕获异常
捕获异常通过3个关键字来实现的:try-catch-finally,用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕获(catch)并处理它,最后一步是通过finally语句为异常处理提供一个统一的出口。只要有finally就一定执行不管有没有异常。
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test02 {
public static void main(String[] args) {
FileReader reader = null;
try{
reader = new FileReader("d:/a.txt"); // 文件是不存在的
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println(""+ c + c2);
} catch (FileNotFoundException e){ // 捕获异常子类在前,父类在后
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
} finally {
try{
if(reader!=null){
reader.close();
}
} catch (IOException e ){
e.printStackTrace();
}
}
}
}
异常处理方式二声明异常
当CheckedException产生时,不一定要立刻处理它,可以再把异常throws出去。
try-with-resource自动关闭closable接口的资源
自动关闭接口的资源
//与上面try-catch-finally相对比,少打了许多代码
import java.io.FileReader;
public class Test03 {
public static void main(String[] args) {
try(FileReader reader = new FileReader("d:/a.txt");){
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c +c2);
}catch(Exception e){
e.printStackTrace();
}
}
}
利用百度解决异常问题
- 细心查看异常信息,确定异常种类和java代码行号
- 确定上下文的一些关键信息
- 拷贝异常信息到百度,查看相关帖子,寻找解决思路
泛型(Fenerics)
概念: 泛型的本质是“数据类型的参数化”,处理的数据类型不是固定的,而是可以作为参数传入,我们可以把“泛型”理解为数据类型的一个占位符(类似:形式参数),即告诉编译器,在调用泛型时必须传入实际类型,这种参数类型可以用在类、接口和方法中,分别被称为泛类型、泛接口、泛型方法。
- 把类型当作参数传递
- <数据类型>只能是引用类
泛型的好处: 不使用泛型的情况下,我们可以使用Object类型来实现任意的参数类型,但是在使用时我们需要进行强制类型转换,这种会导致编译时发现不了错误,只能在运行发生错误。使用泛型之后就可以在编译器识别这种错误,有了更好的安全性,同时所有类型转换由编译器完成。-----1、代码可读性更好(不用强制类型转换)2、程序更加完全【只要编译时期没有警告,运行时期就不会出现ClassCastException】
类型擦除: 泛型主要用在编译时期,用完会被去掉,运行时java虚拟机并不知道泛型。
泛型的使用:
泛型类就是把泛型定义在类上,当用户使用该类的时候,才把类型明确下来。
1.1定义泛型
public class Generic<T> {
private T flag;
public void setFlag(T flag){
this.flag = flag;
}
public T getFlag(){
return this.flag;
}
}
1.2测试
public class Test {
public static void main(String[] args){
Generic<String> generic = new Generic<>();
generic.setFlag("admin");
String flag = generic.getFlag();
System.out.println(flag);
Generic<Integer> generic1 = new Generic<>();
generic1.setFlag(100);
Integer flag1 = generic1.getFlag();
System.out.println(flag1);
}
}
泛型接口:
泛型接口和泛型类的声明方式一致,泛型接口的具体类型需要在实现类中进行声明。
定义:
public interface 接口名<泛型表示符>{
}
//创建接口
public interface Igeneric<T> {
T getName(T name);
}
//通过类实现接口
public class Ignericlmpl implements Igeneric<String>{
@Override
public String getName(String name){
return name;
}
}
public class Test02 {
public static void main(String[] args) {
//通过接口实现类来实现
Ignericlmpl igeneric = new Ignericlmpl();
String name = igeneric.getName("zc");
System.out.println(name);
//通过接口来实现
Igeneric<String> igneric1 = new Ignericlmpl();
String a = igneric1.getName("dasd");
System.out.println(a);
}
}
1、泛型方法
**泛型方法是指将方法的参数类型定义成泛型,以便在调用时接收不同类型的参数。**类型参数可以有多个,用逗号隔开,如<K,V>.定义时,类型参数一般放到返回值前面。
调用泛型方法时,不需要像泛型类那样告诉编译器是什么类型,编译器可以自动的推断出来。
2、非静态方法
//定义一个非方法
public class MethodGeneric {
//无返回值的,定义的格式
public <T> void setName(T name){
System.out.println(name);
}
//有返回值的
public <T> T getName(T name){
return name;
}
}
public class Test3 {
public static void main(String[] args) {
MethodGeneric methodGeneric = new MethodGeneric();
methodGeneric.setName("zc");
methodGeneric.setName(123);
MethodGeneric methodGeneric1 = new MethodGeneric();
String name = methodGeneric1.getName("zc");
Integer name1 = methodGeneric1.getName(123);
System.out.println(name);
System.out.println(name1);
}
}
3、静态方法中使用泛型时需要注意:静态方法无法访问类上定义的泛型。
public class Generic<T> {
private T flag;
//静态方法中无法使用类上定义的泛型
// public static T demo(){
// return null ;
// }
}
//注意比对静态方法和非静态方法的定义格式
public class MethodGeneric {
//定义的格式
public <T> void setName(T name){
System.out.println(name);
}
public <T> T getName(T name){
return name;
}
//静态方法定义
public static <T> void setFlag(T flag){
System.out.println(flag);
}
public static <T> T getFlag(T flag){
return flag;
}
}
//测试静态方法
//静态方法调用不需要实例化
public class Test4 {
public static void main(String[] args) {
//静态方法的调用是不需要实例化的,直接调用类名
MethodGeneric.setFlag("zc");
MethodGeneric.setFlag(123);
String flag =MethodGeneric.getFlag("bjxut");
Integer flag1 = MethodGeneric.getFlag(123);
System.out.println(flag);
System.out.println(flag1);
}
}
4、泛型方法与可变参数
在泛型方法中,泛型也可以定义可变参数类型
//类
public class MethodGeneric{
public <T> void methos(T...arg){
//增强for循环
for(T a:arg){
System.out.println(a);
}
}
}
//测试
public class Test5{
public static void main(String[] args){
MethodGeneric methodgeneric = new MethodGeneric();
//数组的静态初始化
String[] a1 = new String[]{as"","asd","asf"};
Integer a2 = new Integer[]{1,2,3};
methodgeneric.methods(a1);
methodgeneric.methods(s2);
}
}
5、通配符和上下限定
5.1无界通配符
"?"表示类型通配符,用于代替具体的类型,它只能在<>中使用
定义方式
public void showFlag(Generic<?> generic){
}
public class Generic<T> {
private T flag;
//静态方法中无法使用类上定义的泛型
// public static T demo(){
// return null ;
// }
public void setFlag(T flag){
this.flag = flag;
}
public T getFlag(){
return this.flag;
}
}
//通过这个类的showFlag方法去输出Generic的值。
public class ShowMsg {
public void showFlag(Generic<?> generic){
System.out.println(generic.getFlag());
}
}
//测试代码,从下面代码中可以看出,Generic可以指定任意的数据类型
public class Test6 {
public static void main(String[] args) {
ShowMsg showmsg = new ShowMsg();
Generic<Integer> generic = new Generic<>();
generic.setFlag(20);
showmsg.showFlag(generic);
Generic<Number> generic1 = new Generic<>();
generic1.setFlag(50);
showmsg.showFlag(generic1);
Generic<String> generic2 = new Generic<>();
generic2.setFlag("sda");
showmsg.showFlag(generic2);
}
}
5.2通配符的上限限定
上限限定表示通配符的类型是T类以及T类的子类或者T接口以及T接口的子接口。该方式同样适用于与泛型的上限限定。通俗的意思就是:<? extends Number>类型只能是Number或者和它的子类
public void showFlag(Generic<? extends Number> generic){
}
public class Generic<T> {
private T flag;
//静态方法中无法使用类上定义的泛型
// public static T demo(){
// return null ;
// }
public void setFlag(T flag){
this.flag = flag;
}
public T getFlag(){
return this.flag;
}
}
//对Generic的类型做一个上限限定
public class ShowMsg {
public void showFlag(Generic<? extends Number> generic){
System.out.println(generic.getFlag());
}
}
与上个Test6相比,因通配类继承了Number,所以在用Generic类声明一个generic对象时,泛型只能是Number类及其子类
public class Test6 {
public static void main(String[] args) {
ShowMsg showmsg = new ShowMsg();
Generic<Integer> generic = new Generic<>();
generic.setFlag(20);
showmsg.showFlag(generic);
Generic<Number> generic1 = new Generic<>();
generic1.setFlag(50);
showmsg.showFlag(generic1);
}
}
5.3通配符的下限限定
与上限限定相反,但是此方法不适用泛型类
public void showFlag(Generic<? super Number> generic)
总结
- 泛型主要用于编译阶段,当编写成class文件时,JVM虚拟机运行中没有泛型这个概念。
- 基本类型不能用于泛型
Test<int>t
这样是错误的,应使用包装类Test<Integer>t
;
3.不能通过类型参数创建对象