Java-Java中的基本运算及简单算法

主要内容有:Java面向对象基础,日期处理、方法的重载和重写、类的属性和方法的访问控制、类与方法的修饰符、集合、反射、内部类、异常、GUI图形编程、多线程、求两个数的最大公约数与最大公倍数、常见的位运算等。

Java面向对象基础

面向对象的思想:

封装、继承、多态

1.封装:隐藏对象的属性和方法 private
2.继承:对象重用 减少代码冗余 extends,单继承 将父类的属性和方法 继承到子类中

3.多态:同一个类域(存在继承关系的类)的不同对象在调用相同方法的时候表现不同

修饰符 public protected private 无 修饰属性和方法
public :其他类可以任意访问 自己类可以访问
protected:自己访问 子父类之间 相同包下
无:自己访问 相同的包下

单例模式:在整个虚拟机中只有一个类的实例

专门处理日期

java.util.Date 濒临灭绝
java.util.Calendar 不能new
//指向系统当前时间
Calendar cal=Calendar.getInstance()
//获取年份
cal.get(Calendar.YEAR);
//获取月份
cal.get(Calendar.MONTH);

extends 后只能有一个父类:

this 表示当前类的实例
this.属性
this.方法(参数)
this();调用构造函数
this(参数):

方法的重载和重写

重载:在一个类内有多个相同(名字上)的方法
参数类型不同。参数个数不同。参数的顺序不同。
返回值:返回值是否相同对重载不构成影响

Person{
    public void print(){}
    public void print(String message){}
    public void print(int level){}
}

构造函数也可以重载:

重写:发生在子类 。重新定义父类中的方法。
方法签名要跟父类相同
方法签名:返回值+方法名+方法参数(个数,顺序,类型 都相同)
super:访问父类中的属性和方法
super.父类属性
super.父类方法(参数)
super()//父类的构造器
super(参数)//调用父类的重载构造器

方法的参数传递

1.值传递:对于基本的参数类型 值拷贝(把外围的值拷贝到方法内供方法使用,对方法外的变量不构成影响)
2.引用传递:地址值

类的初始化:

静态初始化代码段: static {}
实例初始化代码段: {}

接口:

interface 来声明。只允许定义常量 (public static final String str="abc")和 空方法(抽象方法,没有实现)

public interface Test {
    public void test(String test);
}

接口的作用:用来描述规范,被其他的接口或者类 实现或者继承

具体的类 实现(implements)

接口(一个或者多个,多个之间用","分割),必须实现接口内的所有方法
接口 继承(extends) 接口
接口不能被实例化。接口在一定程度上弥补类java的单继承

抽象类:

如果一个类没有完全的实现接口中的所有的方法,必须把没有实现的方法声明为抽象方法。。(abstract)
如果一个类中有一个抽象方法,那么该类必须被声明为抽象类(public abstract class)
功能更普通类是一样,抽象类可以分担子类的一本分功能

方法 实例化 创建引用

实体类: 全部实现 可以 是
抽象类: 部分实现 不可以 是
接口: 全部不实现      不可以 是

Son son=new Son();
Father son=new Son();
Son s=(Son)son;如果没有就报错:ClassCastingException

因为 Son 继承 Father
Father -> Son

抽象类 -> 继承了抽象类的具体类
接口-> 实现接口的具体类

casting: 类型转换,引用或者类类型
向上转换:不需要显示的类型转换
向下转换:要显示的强制类型转换
上:father
下:son

例:员工管理:

对于员工:cr(retravel)ud
DML insert
DDL drop
存放员工的数据结构-》queue

EmppoyeeDate{ Employee [] emArray;
create();//增加员工
find(int id);
update 更新
delete
}

Java中类的属性和方法的访问控制

类没有protected和private修饰符
被public 修饰的类,可以被其它包中的类访问
没有被public 修饰的类,不能被其它包中的类访问
同一包中,不能访问其它类的private 属性和方法
同一包中,可以访问其它类的默认 属性和方法
同一包中,可以访问其它类的protected 属性和方法
同一包中,可以访问其它类的public 属性和方法
同一包中,不能访问父类的private 属性和方法
同一包中,可以访问父类的默认 属性和方法
同一包中,可以访问父类的protected 属性和方法
同一包中,可以访问父类的public 属性和方法
不同包中,无法访问不同包的其它类的private 属性和方法
不同包中,无法访问不同包的其它类的默认 属性和方法
不同包中,无法访问不同包的其它类的protected 属性和方法
不同包中,可以访问不同包的其它类的public 属性和方法
不同包中,无法访问父类的private 属性和方法
不同包中,无法访问父类的默认 属性和方法
不同包中,无法访问父类的protected 属性和方法
不同包中,可以访问父类的public 属性和方法
可以看到,类中的默认的属性和方法为protected修饰的

static

1.修饰属性:所有的类的实习共享同一个属性
2.修饰方法:类名.方法名(调用方法)
3.{};用来初始化类的static属性

规则:
static修饰的方法不能访问非static变量(成员变量)
static修饰的方法不能访问非static方法(成员方法)

Final修饰符

final:提高程序的健壮性
1.修饰类 该类不能被继承 (java.long.String 不能有子类)
2.修饰属性,改属性为常量 (程序运行期间值不能被改变的叫常量) 常量的赋值:在第一次被赋值之后,永远不能改变。常量的命名:全部大写 用下划线分隔 MAX_SIZE
3.修饰方法 该方法不能被重写

StringBuffer

StringBuffer 提高效率
缓存:提高效率
String : 做频繁的字符串连接操作,非常浪费系统空间
String str="abc";
str+="xyz";
str="abcxyz";
StringBuffer str=new StringBuffer("abc");
str.append("xyz");
str.toString()->StringBuffer->String;

StringBuilder与StringBuffer
StringBuilder和StringBuffer 使用方式完全相同

StringBuffer 线程安全
对象的比较
对象的比较:== 对于引用来说比较的地址值 。对于基本类型比较的数值
比较对象的内容:equals方法

Person p1 = new Person("briup",13);
Person p2 = new Person("briup",13);
p1.equals(p2) -> true :内容相同 false ->内容不同

equals的来源:java.long.object ,默认实现相当与== , 重写该方法完成自定义的内容比较

public boolean equals(Object obj){
    if(obj=null)
        return false;
    if(this=obj)
        return true;
    if(this.getClass()!=obj.getClass())
        return false;
    Person p1=(Person)obj;
    return this.getName().equals(p1)&&this.getAge()==p1.getAge();
}

代码覆盖率:测试用例是否可以覆盖(执行)所有代码

Java集合、反射、内部类、异常

集合(collection)

管理若干个对象
List:管理重复对象
1.Aarraylist:基于数组的实现
2.LinkedList:基于链表的实现

Set:管理不可重复的对象
1.HashSet:检索快
2.TreeSet:排序(自定义规则)

Map:做检索功能。键值对。key->value

对集合进行遍历

迭代器:
java.util.Iterator{
    boolean hasNext();//判断是否存在下一个元素
    Object nest();//取下一个元素
}
fot(int i=0;i<3;i++){
    it.next();
}
Object obj=it.next();
println(obj);

List:放置可重复的对象
Set :放置不可重复的对象 有对象的equals方法(返回true)和hashCode方法(返回的int值相等)决定。
HashSet:
TreeSet:

hashCode来源于object对象
Object obj=new Object();
System.out.println(obj);

java.lang.Object@adfasdf123(由hashCode方法返回);

TreeSet:在向集合中添加元素的同时进行排序。对放入treeSet中的对象实现comparable接口并实现compareTo方法
Person 排序:
p1.compareTo(p2):p1>p2 return 1;p1=p2 return 0; p1<p2 return -1;
先排name :String类型按字母表的数序
如果相等,再按age

Map:->HashMap 键值对 key-》value
key value 可以是任何的object
一般情况下使用String作为key,value用Object
"bringup-1" à new Person("bringup-1",true,1);
存:put (key,value)
取:get(key)返回value

map遍历的两种方式:
1.获取map中所有的key值 :map.keySet();
2.Map.Entry封装了key 和value

反射:reflection

使用反射来处理class文件
java.lang.reflect.*;
Class{//描述一个类
Field//描述类中的属性
Method//描述类中的方法
Constructor//描述类的构造函数
}

反射的作用:
1、修改虚拟机中对象的属性(非常规)可以直接修改private属性,person.setName();
2、条用对象的方法(非常规)person.toString();
3、不通过new来创建类的对象的实例new Person();

获取类的class实例:
1、Class clz=Class.forName("ch06.Person");//需要处理异常
2、类的引用.getClass(); Class clz=p1.getClass();
3、类名.class Class clz=Person.class;
4.类名.getSuperClass() Class clazz=p1.getSuperclass();
5.primitive wraper classes的.TYPE语法,用于得到基本类类型:class clazz=Integer.TYPE;

动态的创建类

不通过new来创建类的对象的实例:通过字符串形式命名,将类名迁移到配置文件中(通常是文本文件形式),根据横序的运行,动态的创建类得实例
Constructor constructor =clz.getConstructor(String.class, boolean.class, int.class);
Object obj=constructor.newInstance("briup-000",false,100);
System.out.println("Constructor a new instance without new :" +obj);

内部类
//解耦:数据跟程序解耦
//高内聚,低耦合
内部类:类里面的另外的类 。 共享外部类的资源;有效的避免命名冲突

静态内部类:
不许要创建外部类的实例即可创建内部类实例。可以到达一定程度的封装

局部内部类:
类可以写在任意的地方

异常(Exception)

1.异常
异常:程序无法正常运行 程序当中的错误
异常处理的机制:遇到异常代码,jvm寻找异常处理,如果找不到异常处理语句,则将该异常抛出至上层代码,如此反复,直至抛给虚拟机,终止程序运行

异常的分为两类:checked 异常(继承java.lang.Exception的异常(在代码中必须处理))。unchecked异常(java.lang.RuntimeException(不许要在程序编译的时候处理))
checked:编译期检查 如果源代码中没有进行处理,则无法通过编译
unchecked:运行期检查 编译的不会检查
Class.forName()->ClassNotFound

对于异常的处理:
1.try{//一般来说出来checked异常
    //+可能有问题的代码
}catch(异常的类型1){
    //+处理异常的代码
}catch(异常的类型1){
    //+处理异常的代码
}finally{
    //+必须执行的代码段 通常用来回收资源
}

2.throw 异常类型
return和finally(无论代码是否异常。都只返回finally的return)

3.自定义的异常:
一般都是unchecked;阐述系统中的业务逻辑错误
UersNotFoundException:找不到数据的用户
if(user==null)
throw new UserNotFoundException;
throw new NullPointerException;

断言

断言:在程序运行过程中进行debug
偏向于测试
assert 布尔表达式(返回false的时候抛出AssertionError);
assert 布尔表达式:"断言信息";
开启断言:java-ea ch07/Test
当没开启断言的时候,对程序的效率没有任何影响
判断程序运行过程中变量的值是否符合预期

public class AssertTest{
    public static void main(String args[]){
        System.out.println("Before");
        assert 1==1;
        assert 1!=1:"wrong !!!";//类似于自定义异常的有参的函数构造
        System.out.println("After");
    }
}

判断程序运行的参数是否是"briup",如果不是则抛出异常

GUI 图形编程

容器:用来存放组件或者子容器
顶级容器:只能存放组件或者其它子容器(javax.swing.Jframe)
子容器:可以被其他容器所包含 也可以包含其他组件或者容器(javax.swing.JPanel)
组件:按钮。文本框。菜单 在javax.swing.*;包下
布局:用来表示组件或者容器的相对位置

1.FlowLayout 流式布局 组件顺序拜访
2.BorderLayout 边框布局 5个部分:south north west east center
3.GridLayout 表格布局 以行和列的形式将组件组织在一起

多线程

java优点:跨平台 多线程
进程:在os运行一个程序 用来完成一个独立完整的任务 至少要有一个线程(主线程)
线程:将一个完整的任务分解成若干的独立的小任务来完成 (本质)更多的抢占cpu的时间片,达到并怕执行的效果

计算机在同一时刻只能执行一条指令(单核)
线程由进程衍生出来。地址空间共享。data共享。code共享。是独立运行的分支(程序流)

java中如何实现线程:
1.继承Thread类
2.实现Runnable接口 解决单继承

都要实现run(),线程所要做的事情
public void run(){
}

如果run方法调用结束,线程结束
启动线程:线程的引用.start();

普通线程和精灵Deamon线程
Thread.setDeamon(boolean);//设置普通线程为Deamon线程
Deamon线程:在后台运行的线程。对于Deamon线程始终依赖(生命周期)与另外一个线程

普通线程不存在依赖关系
setDeamon()必须在start();之前调用

线程的优先级:如果优先级不同,那么线程运行的先后顺序可以不一样(取决于操作系统的调度程序)
Thread.setPriority(0-10);
java.lang.Thread
Thread.sleep();让线程暂时停止运行某一特定的时间
Thread t=Thread.currentThread();获取当前运行的线程的实例(静态方法)

停止线程:不建议使用stop。可以设置标志位,通过对标志位的读取来终止线程的运行
boolean flag=true;
if(!flag)
return;

线程同步

线程同步:多个线程操作同一个对象的时候
1.为了保证多个线程操作同一个对象的完整性,可以对需要同步的方法使用synchronized修饰
2.使用synchronized修饰的方法,在调用的时候必须先获得该对象的锁(一个对象只有一把锁),只有获得了锁之后,同步方法才能被调用,调用之后锁被自动的释放

3.修饰代码块
synchronized(对象的引用){
需要同步的代码
}
传入的对象的引用被synchronized加锁。降低加锁的粒度。

思索:deadlock 当两个对象相互持有对方所需要的锁的时候,并且都得不到释放,这时候产生死锁。。。。。。

wait():释放对象的锁 java.lang.Object
对象的引用.wait();释放引用锁指向的对象的锁,使当前程序停止运行,等待其他线程调用notify()进行通知后方可运行

sleep()不会释放对象的锁

Java中的常见的基本算法

求两个数的最大公约数与最大公倍数

public class MaxDivisor {
    public static void main(String[] args) {
        MaxDivisor opt = new MaxDivisor();
        //System.out.println(Integer.valueOf(args[0])%Integer.valueOf(args[1]));
        System.out.println("最大公约数为:" + opt.commonDivisor2(Integer.valueOf(args[0]), Integer.valueOf(args[1])));
        System.out.println("最小公倍数为:" + opt.commonMultiple(Integer.valueOf(args[0]), Integer.valueOf(args[1])));

        //问号表达式
        int b = Integer.valueOf(args[0]);
        int a = (b == 0 ? b : (b + 2));

        System.out.println("opt.ret(b): " + opt.ret(b) + "\na = " + a + " b = " + b);
        System.out.println("Add(a,b) = " + opt.Add(a, b));
        System.out.println("1^1:" + (1 ^ 1));    //得0
        System.out.println("0^0:" + (0 ^ 0));    //得0
    }

    //测试问号表达式
    public int ret(int b) {
        return b == 0 ? b : (b += 2);
    }

    //最大公倍数
    public int commonDivisor1(int num1, int num2) {
        return (num1 % num2 == 0) ? num2 : commonDivisor1(num2, num1 % num2);
    }

    public int commonDivisor2(int num1, int num2) {
        int t, a;
        if (num1 < num2) {
            //shift1(num1,num2);
            //shift2(num1,num2);
            shift3(num1, num2);
        }
        while ((a = num1 % num2) != 0) {
            num1 = num2;
            num2 = a;
        }
        return num1;
    }

    //最小公倍数
    public int commonMultiple(int num1, int num2) {
        return num1 * num2 / commonDivisor1(num1, num2);
    }

    //交换函数
    public void shift1(int num1, int num2) {
        int t = num1;
        num1 = num2;
        num2 = t;
    }

    public void shift2(int num1, int num2) {
        num1 = num1 + num2;
        num2 = num1 - num2;
        num1 = num1 - num2;
    }

    public void shift3(int num1, int num2) {
        num1 = num1 ^ num2;    //异或,相同为0,不同为1,找出不同的位(异或之后,为1的位),
        num2 = num1 ^ num2;    //再异或得到初始num1的值赋给num2
        num1 = num1 ^ num2;    //再异或得到初始num2的值赋给num1
        //num2的各位与0异或(两数中相同的位)保持不变,num2的各位与1异或(两数中不相同的位)反转,
    }

    //位运算实现加法
    public int Add(int num1, int num2) {
        return num2 == 0 ? num1 : Add(num1 ^ num2, (num1 & num2) << 1);
        //先不计进位相加(num1^num2),得出的结果,再与进位相加,随着递归,直至进位变为0,递归结束
    }
}

杨辉三角

public class YHTest {
    public static void main(String[] args) {
        int[][] array = new int[10][10];
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j <= i; j++) {
                if (j == 0 || i == j)    //如果是第一列或者对角线
                {
                    array[i][j] = 1;
                } else {
                    array[i][j] = array[i - 1][j - 1] + array[i - 1][j];
                }
                System.out.print(array[i][j] + "\t");
            }
            System.out.println();
        }
    }
}

获取当前日期

public class CalendarTest {

    public static void main(String[] args) {
        //获取当前日期
        Calendar cal = Calendar.getInstance();
        cal.get(Calendar.YEAR);        //得到当前日期的年份
        cal.get(Calendar.MONTH);    //得到当前日期的月份
//        cal.set();    //设置日期
    }
}

常见的位运算

public class Test1 {
    public static void main(String[] args) {
        System.out.println("~2=" + (~2));//取反
        System.out.println("2&3=" + (2 & 3));//与
        System.out.println("2|3=" + (2 | 3));//或
        System.out.println("~-5=" + (~-5));//取反
        System.out.println("-3^3=" + (-3 ^ 3));//异或

        //算术右移:低位溢出,符号位不变,并用符号位补溢出的高位
        //算术左移:符号位不变,低位补0
        //逻辑右移:低位溢出,高位补零
        System.out.println("1>>2=" + (1 >> 2));
        System.out.println("-1>>2=" + (-1 >> 2));
        System.out.println("1<<2=" + (1 << 2));
        System.out.println("-1<<2=" + (-1 << 2));
        System.out.println("3>>>2=" + (3 >>> 2));//逻辑右移
    }
}

/*
~2=-3
2&3=2
2|3=3
~-5=4
-3^3=-2
1>>2=0      //算术右移
-1>>2=-1
1<<2=4      //算术左移
-1<<2=-4
3>>>2=0     //逻辑右移
*/

利用位操作相加、相减、逻辑右移、算术右移、循环左右移及由原码求补码

public class d2binary {
    public static void main(String[] args) {
        int a = 10;
        for (int i = 31; i >= 0; i--) {
            System.out.print(a >> i & 1);    //输出二进制
        }
        System.out.print("\n\n");

        d2binary op = new d2binary();

        int b = 15;
        int c;

//        c=op.add(1,1);
//        System.out.println("\nAdd(10,15)-->c="+c);

    }

    /*交换两个变量的值,有三种方法:
    1.利用位操作(异或 ^)
    2.两数相加、相减、相减
    3.使用中间变量
    */

    //利用位操作交换两变量的值
    public void shift3(int num1, int num2) {
        num1 = num1 ^ num2;    //异或,相同为0,不同为1,找出不同的位(异或之后,为1的位),
        num2 = num1 ^ num2;    //再异或得到初始num1的值赋给num2
        num1 = num1 ^ num2;    //再异或得到初始num2的值赋给num1
        //num2的各位与0异或(两数中相同的位)保持不变,num2的各位与1异或(两数中不相同的位)反转,
    }

    //从32位的单元中取出某几位
    public int getMidBits(int val, int n1, int n2) {
        int z;
        z = ~0;    //将z初始化16位的1
        z = (z >> n1) & (z << (32 - n2));    //将两端的化成0,中间的化成1
        z = val & z;
        z = z >> (32 - n2);
        return z;
    }

    //对32的二进制数取出它的奇数位(从左边起1,3,5 。。。)
    public int getOddBits(int val) {
        int z, a, q;
        z = 0;
        for (int i = 1; i <= 31; i += 2) {
            q = 1;
            for (int j = 1; j <= (32 - i - 1) / 2; j++)    //要取的数的位数为原来的数的位数的1/2
                q = q * 2;        //原数进位指针进两位,要取的数的指针进一位
            a = val >> (32 - i);    //将第i个位置的数移到最低位
            a = a << 31;        //通过左移31位,将将最低位移到最高位去,其后的位全都补0
            a = a >> 31;        //右移31位,将最高位移到最低,其前面的位全都补零,得到第i位
            z = z + a * q;        //积加取出的数
        }
        return z;
    }

    //算术右移:低位溢出,符号位不变,并用符号位补溢出的高位
    //算术左移:符号位不变,低位补0
    //逻辑右移:低位溢出,高位补零

    //实现算术右移函数
    public int shiftRightArithmetic(int val, int n) {
        int z;
        z = ~0;
        z = z >> n;
        z = ~z;
        z = z | (val >> n);
        return z;
    }

    //实现逻辑右移函数
    public int shiftRightLogical(int val, int n) {
        int z;
        z = (~(1 >> n)) & (val >> n);
        return z;
    }

    //实现右在循环移位
    public int moveRightCircle(int val, int n) {
        int z;
        z = (val >> n) | (val << (32 - n));
        return z;
    }

    //实现左循环移位
    public int moveLeftCircle(int val, int n) {
        int z;
        z = (val >> (32 - n)) | (val << n);
        return z;
    }

    //根据原码求补码(求二进制数的补码)
    public int realBits2MaskBit(int val) {
        int z;
        z = val & 10000000;
        if (z == 10000000)
            z = ~val + 1;
        else
            z = val;
        return z;
    }
    //一个正数的补码等于该数的原码,一个负数的补码等于该数的反码加1
}

版权所有,转载请注明出处 luowei.github.io.