数据类型 | 所占字节 |
---|---|
byte | 1 |
short | 2 |
int | 4 |
long(定义long型数据时加后缀“L”) | 8 |
float | 4 |
double | 8 |
char | (一般为2)不一定,详见https://blog.csdn.net/qq_21125183/article/details/85236267 |
boolean(java规范中并没有定义boolean类型的大小) | (查阅其他博客)单个的boolean再JVM中占4个字节,在数组中每个boolean在JVM中占1个字节 |
1.自动类型转换的等级(由低到高):byte,short ,char—> int —> long —> float —> double
2.byte,short,char在一起运算时,首先转换为Int类型。
如这样的代码就会提示类型不匹配的错误:
public class Client {
public static void main(String args[]) {
byte b1 = 5;
short s1 = 6;
short s2 = b1+s1;//会有类型不匹配的错误,提示你进行cast
}
}
1.首先你要知道java中的权限关键字有:private,default(其实就是默认的),protected,public
2.其次java和c++的权限关键字是不一样的,java有default而c++没有
3.上表格
关键字 | 本类及其内部方法 | 同一个包的类 | 继承类 | 其他类 |
---|---|---|---|---|
private | 可 | 不可 | 不可 | 不可 |
default | 可 | 可 | 对于子类:若和它在一个包里则可调用,不和它在一个包里不能调用 | 不可 |
protected | 可 | 可 | 只要是子类,不管在不在一个包里都可以调用 | 不可 |
public | 可 | 可 | 可 | 可 |
4.另外一定要注意,这里的default是不能声明出来的,比如如果一个类中有
default int x;则会报错,这个default意思就是不添加任何权限修饰词,int x。
另外default关键字只用在2个地方
(1)switch
(2)Interface的方法修饰词,(可以让虚拟方法有方法体),具体想了解详细的话,查阅这个博客
link.
注意一点,子类继承父类之后的堆内存中分为super区和this区
看这样一个例子:
public class Client {
public static void main(String args[]) {
//Father father = new Father();
Son son = new Son();
System.out.println(""+son.getA());
}
}
public class Father {
private int a = 1;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
public class Son extends Father{
private int a = 3;
}
最后的输出结果是1
这个知识点详见:link.
例如这样一个语句Son son = new Son();
这句话在执行的时候可以把son理解成一个指针,存在栈中,它应该指向一个Son的对象(注意这个“应该”两个字,为后文中的向上转型做了铺垫哦),此处它指向堆里的一片内存区域,这个内存区是一个Son的对象,(因为new之后是一个Son的对象),它在访问Son类中的方法或属性的时候,先在this区进行寻找,如果找到了则执行,找不到再去super区寻找。
子接口extends父接口,不能用Implements,并且一个子接口可以extends多个父接口。
虚拟类implements接口,不能用extends
继承与static:
1.父类中的static方法:可以继承,可以重写,但是子类不能用非静态方法重写静态方法,会报错
2.父类中的static变量:可以继承,可以重写,若是子类中有一个与父类同名的非静态变量,比如父类有static int a ,子类有int a,则子类不再有static int a,但是super区仍然有static int a 。
此时直接用类名调用Son. 的时候会提示有a,但会显示属于Father
3.向上转型的时候:会调用父类的static方法及变量
(1):方法的重载以及覆写
(2):对象的多态性
1…向上转型:
父类的声明却接收一个子类对象(也可以说成,用父类声明,用子类实例化),如代码所示
public class Father {
public void print() {
System.out.println("father");
}
}
public class Son extends Father{
@Override
public void print() {
System.out.println("son");
}
public void printSon() {
System.out.println("printSon");
}
}
public class Client {
public static void main(String args[]) {
Father father = new Son();
father.print();
}
}
输出结果为:
son
值得注意的是这时候这个father是不能调用Son类型中的printSon()方法的,把这个father看成一个指针,它的类型是Father,所以在索引的时候,他能寻找的属性和方法(可以理解为按名字寻找)只有Father类中的属性和方法,但是在它指向的堆内存是一个Son的对象,前面说过了,在堆中寻找的时候先在this区进行寻找。
但其实它的本质是一个Son的对象,
当我加上这一行代码时
System.out.println(father.getClass().getSimpleName());
下面多输出了这样一条语句
Son
所以证明了它的本质还是一个Son的对象。
2.向下转型
值得注意的是直接向下转型是会报错的(其实这样根本不是向下转型的定义),如
Son son = new Father();//会报错
可见这样是会报错的
来看真正的向下转型
Father father = new Son();
father.print();
Son son = (Son) father;
son.print();
son.printSon();
输出结果
son
son
printSon
这个我就不再具体解释了,要学会举一反三嗷。
首先声明一下,这里大多数是我们老师的课件,我拿来整理总结了一下,(我这菜鸡水平哪有这么厉害)
这里为了应付考试,有以下几种恶心人的地方(是真的恶心)
出现异常时,加入try catch语句后,try{}捕获语句中出现异常后,try中这句话后面的语句不再执行,直接跳转到对应的catch,在该catch执行后,继续执行try…catch后的语句,上代码:
package edu.hit;
public class Demo3_Exception {
public static void main(String[] args) {
Demo2 d = new Demo2();
try {
int x = d.div(10, 0);
System.out.println(x);
} catch (ArithmeticException a) { // ArithmeticException a = new ArithmeticException();
System.out.println("出错,除数为零");
}
System.out.println("1111111");
}
}
class Demo2 {
public int div(int a, int b) {
return a / b;
}
}
运行结果为
出错,除数为零
1111111
下面这个也能证明这一点:
package edu.hit;
public class Demo4_Exception {
public static void main(String[] args) {
int a = 10;
int b = 0;
int[] arr = { 11, 22, 33, 44, 55 };
try {
System.out.println(a / b);
System.out.println(arr[10]);
arr = null;
System.out.println(arr[0]);
} catch (ArithmeticException e) {
System.out.println("除数不能为零");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界了");
} catch (Exception e) { // Exception e = new NullPointerException();
System.out.println("出错了");
}
System.out.println("over");
}
}
运行结果:
除数不能为零
over
捕获范围小的异常(子类异常)要放在捕获范围大的异常(父类异常)之前;
在开发中,为了简单起见,异常基本都直接使用Exception接收。
如:
public class Demo6_Exception {
public static void main(String[] args) {
int a = 10; int b = 0;
int[] arr = { 11, 22, 33, 44, 55 };
try {
System.out.println(a / b);
System.out.println(arr[10]);
} catch (ArithmeticException e) {
System.out.println("除数不能为零");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界");
} catch (Exception e) { //用超类对象接收任何子类对象 System.out.println("出错");
}
System.out.println("over");
}
}
(1):finally{} 语句增加了一个统一处理的出口操作,无论是否发生异常,程序都要执行finally {}语句。
(2):finally的作用:用于释放资源,在IO流操作和数据库操作中会见到
(3):特殊情况:在执行到finally之前,在catch中jvm退出 (System.exit(0)),此时直接从catch中退出,并不进入finally语句。
上代码:
public class Demo8_Exception{
public static void main(String[] args) {
System.out.println(method());
}
public static int method() {
int x = 10;
try {
x = 20;
System.out.println(1 / 0);
return x;
} catch (Exception e) {
x = 30;
return x;
} finally {
x = 40;
System.out.println("finally");
System.out.println(x);
//return x; //如果在这里面写返回语句,那么try和catch的结果都会被改变
}
}
}
运行结果是
finally
40
30
怎么来解释呢:
首先因为第二个输出的是30,这个方法的返回值肯定是30
仔细看,在try中的println发生异常后,后面的return x不会被执行;
然后到catch语句中x=30,这时候要return,但是方法不会先return,而是先执行完finally的语句
但是为什么x=40不是这个方法的返回值呢,这个先记住,(应付考试),在弄懂了之后会再写博客。
如果把最后一句的注释去掉,改成
return x;
结果是:
finally
40
40
1.getMessage():
获取异常信息,返回字符串
2.toString():
获取异常类名和异常信息,返回字符串。
3.printStackTrace():
获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void
package edu.hit;
public class Demo9_Throwable {
/**
* * A:Throwable的几个常见方法
* a:getMessage() 获取异常信息,返回字符串。
* b:toString()获取异常类名和异常信息,返回字符串。
* c:printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
* B:案例演示 Throwable的几个常见方法的基本使用
*/
public static void main(String[] args) {
try {
System.out.println(1 / 0);
} catch (Exception e) { // Exception e = new ArithmeticException("/ by zero");
System.out.println(e.getMessage()); //获取异常信息
System.out.println(e.toString()); //调用toString方法,打印异常类名和异常信息
e.printStackTrace(); // jvm默认就用这种方式处理异常
}
}
}
运行结果
/ by zero
java.lang.ArithmeticException: / by zero
java.lang.ArithmeticException: / by zero
at edu.hit.Demo9_Throwable.main(Demo9_Throwable.java:14)
throws关键字主要是用在方法的声明上,表示一个方法并不处理异常,而交给“方法的调用处”进行处理。
throws关键字除了在普通的方法上使用之外,还可以在主方法上。如果在主方法上就表示一旦出现了异常之后,继续向上抛,由JVM进行处理。
懒得说了。。。继承自Exception类,再写一些里面的方法就行了。
首先要明确java中的传参是引用方式传参的,但是结合“栈指向堆”这样一种结构,会有一些时候容易在理解上出错。
有个有趣的例子嗷,详见这一篇博客
链接: link.
1.输入流是指数据源向程序输入数据,输出流是程序向数据宿输出数据
2.而输入是指的程序向文件中输入数据,输出是指从文件中向程序读出数据
(为了应对考试,这些概念上的东西就重复一点,不要嫌我啰嗦)
1.每个数据都必须等待排在它前面的数据读入或送出之后才能被读写;
2.每次读写操作处理的都是序列中剩余的未读写数据中的第一个,不能随意选择输入输出的位置。(注意奥)
3.所有涉及数据流操作的程序都应该添加:import java.io
1.可以分为字节流(8位二进制)和字符流(16位二进制)
2.字节流
(1)流中数据以字节为基本处理单位;
(2)字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的。
3.字符流
(1)流中数据以字符为基本处理单位(16位Unicode码);
(2)字符流只能操作纯字符数据,对字符数据操作比较方便。
2.处理流:又称高级流或包装流,处理流对一个已存在的流进行连接,通过封装后的流来进行读写。
方法名称 | 作用 |
---|---|
abstract int read() | 从流中读入数据 |
int read(byte b[ ]) | 从流中读入数据,并存放到数组b中 |
int read(byte b[ ],int off, int len) | 从流中读入len个字节,并从数组b的off位置开始存放 |
long skip(long n) | l跳过流中若干字节数 |
int available() | 返回流中可用字节数 |
void mark(int readlimit) | 在流中标记一个位置 |
void reset() | 将流重置到标记处 |
boolean markSupport() | 是否支持标记和复位操作 |
void close() | 关闭流 |
1.首先看一些read()方法
方法名称 | 作用 |
---|---|
int read() | 从输入流中读取一个字节的数据,如果已到达文件末尾,则返回 -1(注意这个-1是Int型的-1,因为read()方法的返回值类型就是int类型 |
2.我们来看一个例子
FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
int i;
while((i=fileInputStream.read())!=-1) {
System.out.println(i);
}
这个文件里的数是
那么输出结果是
可以体会到它是按字节读取的,并且是按ascll码值返回的。
2.其实在刚学的时候我是有个问题的,我在想read()方法是按byte类型来读,byte类型的值的范围是【-128,127】,那如果有些字符的ascll码值不在这个范围内那岂不是会出错,这里有这样一个表
可以看到ascll可显示字符都没有超过byte类型的范围。
3.那么问题就出来了,read()方法读取的是一个字节,为何返回是int,而不是byte?
(1)首先来看一下byte类型的-1
-1的原码:10000001
反码11111110
补码11111111
(2)那么假设read()方法的返回值类型是byte,
那如果有一个序列是(随便举的一个例子)
00010100 00100100 01000001 11111111 0000000
那么读到11111111就会返回-1,导致后续的序列都读不出来
(3)所以read()方法要返回Int型,需要在读的每一个八位二进制数前面补24个0
所有遇到-1会变成00000000 00000000 00000000 11111111(这时候的值也就是255)。
Bitmap bitmap = null;
URL url = null;
try {
url = new URL(strings[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
InputStream inputStream = new BufferedInputStream(url.openStream());
OutputStream outputStream = new ByteArrayOutputStream();
/**
* 进度条的操作
*/
long fileLength = conn.getContentLength();//文件总大小
Log.i("MainAV","文件总大小为:"+fileLength);
byte[] data = new byte[1024];//每次读取的大小为2的10次方个字节
long total = 0;//累计读取的大小
int count = 0;//每一次读取的大小
while ((count = inputStream.read(data)) != -1){
total+=count;
Log.i("MainAV","读的百分比:"+(int)(total/(float)fileLength*100));
publishProgress((int)(total*100/(float)fileLength));
outputStream.write(data,0,count);
}
//转化为字节数组
byte[] result = ((ByteArrayOutputStream) outputStream).toByteArray();
bitmap = BitmapFactory.decodeByteArray(result,0,result.length);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
inputStream.close();
outputStream.close():
}
return bitmap;
概念就不再说了,只说一些第一次学的时候没注意到的(再次仔细看一遍书的时候总结了一下)
(1)假如有一个类用了泛型,设为Generation
(2)当然Generation类在被用到的时候,是可以这样声明的(不带泛型):Generation generation,这样其实就是作用(注意是作用)等同于Generation
private void fun(Generation<?> generation){
}
(4)注意这样一点,刚学的时候犯过这样错误
用ArrayList
(5)没找到合适的例子,这里有一个安卓开发中的泛型的应用。
我在用到ViewPager的时候写了这样一个PagerAdapter的基类(注意不是FragmentPagerAdapter)
package com.example.myapplication.Base;
/**
* Created by:马俊豪
* Description:PagerAdapter的基类
*/
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import java.util.ArrayList;
//android中View是所有UI的基类,所有设置泛型T extends View
public class BasePagerAdapter<T extends View> extends PagerAdapter {
private ArrayList<T> viewArrayList;
public BasePagerAdapter(ArrayList<T> viewArrayList){
this.viewArrayList = viewArrayList;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
View view = viewArrayList.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView(viewArrayList.get(position));
}
@Override
public int getCount() {
return viewArrayList.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view==object;
}
}
子类在继承的时候声明好T的类型就欧克了。
没办法,考试是要考类图的绘制的,这里复习顺便总结一下。
这里只说类之间关系对应的类图怎么画
跟着辛国栋老师上课的同学可以在实验三的实验报告里看。
首先看类的关系:
类A实现接口A,这里的接口和类重名了(要注意如果类和接口在一个包里的时候,类和接口不能重名嗷,当然不在一个包里两个类,两个接口,接口和类都是可以重名的)
类A用到了类B,但是关系脆弱,具有偶然性,临时性
举例:类B作为参数被类A在某个method方法中使用
类A用到了类B,但是关系比较强
举例:表现在代码层面,为被关联类B以类的属性形式出现在关联类A中,也可能是关联类A引用了一个类型为被关联类B的全局变量。
类Family包含类Child
关联关系的特例,has-a的关系,整体与部分。
类Person包含类Brain
更强的聚合,人和大脑,除了满足聚合之外,两个类的生命周期也是一样的
(1).类名是Class,如果是虚拟类,则让Class是斜体
(2)里面的参数: 访问权限 参数名称:type = 初始值
“:type = 初始值”这一部分可以有,也可没有
(3)里面的方法:访问权限 方法名称(参数名称:参数类型 = 参数初始值):返回值类型 :返回值默认值
(4)对于访问权限:
public +
protected #
private -
default ~
2.单个Interface
如果一点也不了解的话建议自己去查一查
这里总结一下
1.接口中的default方法,实现类可以重写也可以不重写
2.实现类若继承多个接口,多个接口有两个或两个以上,那么这个接口必须重写这个default方法
3.父类重写之后。子类继承父类的时候会把这个default方法继承,而不是继承接口中的default方法
1.接口中只有public static final的常量,所以也必须初始化,其他都会报错,但是可以直接写 int x = 0;
这样会自动把x的权限转换成public static final,写final int x;,static int x;都会自动转换成public static final int x
但是抽象类不会自动转换,只有接口可以。
2.接口方法:
(1)不加static的时候:
只能是public或者private,(注意如果是private方法则必须有方法体,并且该方法不能是虚拟方法。其实个人的理解这里的private方法就是为了default方法服务的,相当于一个完成一部分功能的函数。)(而public方法是不能有方法体的)。
若是直接写void fun(),会默认为public abstract。
(2)加static的时候:
方法必须有方法体
有三种形式
<1>public static
<2>static(相当于public static)
<3>private static
三种都必须有方法体(显而易见,毕竟是static方法)
接口中static方法不能和final和default一起使用,普通类中可以有static final方法
就写到这里吧,基础东西的主题知识算是复习的差不多了,有些东西真的恶心啊,项目开发不会用到的,但是为了考试和以后的面试,算是尽点力吧。才疏学浅,有什么错误请指出,说不定我能多考几分呢,谢谢