ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javase

2022-08-08 22:01:49  阅读:372  来源: 互联网

标签:String 对象 javase 序列化 方法 public name


1、java语言的特点

面向对象、多线程、跨平台、高效、安全可靠、网络编程

2、什么是字节码?

一个java文件,经过javac命令编译之后就变成了字节码的文件,字节码是由十六进制的值组成,jvm以字节为单位进行读取。java之所以可以一次编写,到处运行,主要是无论在什么平台,都可以编译生成字节码文件给jvm使用。

好处:java通过字节码的方式,在一定程度上解决了解释性语言执行效率低的问题,同时也保留了可移植性的特点。

3、java的数据类型

基本数据类型:byte、short、int、long、float、double、char、boolean

引用数据类型:数组、类型、接口

4、访问修饰符

java通过访问修饰符来控制对变量、方法、类的访问,有四种类型。

  • private(私有):只能作用在当前类当中
  • default(默认,什么都不写):在同一个包内可见
  • protected(保护):作用在当前包和子类
  • public(公共):所有的都可以访问

5、break、continue和return

  • break:跳出所在的当前整个循环,到外层代码继续执行。

  • continue:退出本次循环

  • return:结束方法

6、final、finally和finalize

  • final是java的关键字:是java的关键字,可以修饰变量、方法和类
    • 修饰的变量不可变,必须初始化,通常称被修饰的变量为常量
    • 修饰的方法不能被重写,但是子类可以使用该方法
    • 修饰的类不能被继承
  • finally:作为异常处理的一部分,配合try catch 使用,finally块里面的代码最终都会被执行,无论是否出现异常,但是可以通过system.exit(0)可以阻断finally执行
  • finalize:是java.lang.Object里的方法,也就是说每个对象都有该方法,在垃圾回收的时候调用,只会调用一次。

7、static

static是java的关键字,用在变量、方法和代码块上,随着类的加载而加载,加载过程中完成内存的分配,是属于类的,在不用创建对象实例的情况下可以访问,在本类中可以直接访问,在其他类中可以通过类名.(变量名\方法名)来调用。

  • 静态变量只有一份被加载到内存中,被所有类共享
  • 静态方法中,不能访问实例变量和实例方法(因为还没有创建出来),可以访问静态变量和静态方法

8、java属性的执行顺序

1、父类静态变量和静态代码块(先声明的先执行);

2、子类静态变量和静态代码块(先声明的先执行);

3、父类的变量和普通代码块(先声明的先执行);

4、父类的构造函数;

5、子类的变量和普通代码块(先声明的先执行);

6、子类的构造函数。

9、面向对象和面向过程

面向对象:用代码来高度模拟现实世界。将现实世界的事物抽象成对象,将事物的特征和行为封装在一个类中

面向过程:分析出解决问题的步骤,然后用函数将这些步骤一步一步实现

面向对象的三大特征:

  • 封装:就是把事物封装成类,类内部的实现给隐藏起来了,外界只需要调用方法即可,不用知道怎么实现的。也可以控制可以被谁访问。提高了安全性和代码的组件化思想
  • 继承:子类继承父类的属性和方法,子类拥有父类的属性和方法,并且也可以拥有自己独有的属性何方法(进行扩展)。提高了代码的复用性,

关于继承有几个注意点:

  • 子类有自己的构造器,不能继承父类的构造器
  • 对于父类的私有变量和方法,子类只是拥有,但是不能访问
  • 实现继承后,子类初始化时必须先初始化父类(子类构造器第一行隐藏的代码:super();)

java是单继承:因为如果是多继承,多个父类有相同的属性和方法,子类不知道调用哪一个

一个类默认继承了Object类,要么间接继承了Object类(Object类是所有类的祖宗)

  • 多态:指父类中的属性和方法被子类继承后,可以有不同的数据类型或表现不同的行为。(继承的都是同一个类,但是子类都有自己的实现方式)

多态的实现方式:

父类类型   对象名 = new 子类构造器();
接口类型   对象名 = new 实现类构造器();

实现前提:

  • 必须有继承或者实现关系
  • 必须存在父类类型指向引用类型
  • 有方法重写

10、重载和重写的区别

重载(运行时多态:在编译时,无法确定调用哪个方法,只有在调用方法指定参数时才知道):是方法与方法之间,方法名相同, 参数列表不同。返回类型可以相同也可以不相同;(有参无参构造器)

重写(编译时多态):子类对父类的方法进行重写,方法名、参数列表、返回值都要相同。(override)

11、抽象类和接口的区别

抽象类:被abstract修饰的类叫抽象类;如果一个类中没有足够的信息来描述一个对象,那么这个类就叫做抽象类;

接口:被interface修饰的类,接口是更加彻底的抽象,接口体现的是规范思想,实现接口的子类必须重写完所有的抽象方法。

区别:

  • 抽象类只能被单继承,接口可以多实现

  • 抽象类有构造器,接口没有构造器

  • 抽象类的变量可以使用各种各样类型,接口的变量只能是由public static final修饰的常量

  • 抽象类可以有普通方法,接口只能是静态方法、默认方法和抽象方法

共同点:

  • 都有抽象方法
  • 都不能实例化(创建对象)

12、java创建对象的几种方式

  1. 通过new,调用构造函数创建对象
  2. 通过反射(调用newInstance方法来获取实例)
  3. 使用Object的clone方法
  4. 使用对象输入流ObjectInputStream的readObject方法读取序列化对象(反序列化)

13、什么是不可变对象?

不可变对象是指对象一旦创建出来,状态就不能更改,任何修改都会创建一个新的对象。因为其是不可变的,所以就不存在线程安全问题。

创建一个包含可变对象的不可变对象:String对象是不可变的,但是数组里面的对象是可变的

final String[] str=new String[]{对象1,对象2};

14、值传递和引用传递

值传递:就是基本类型的数据的传递,传递的是值的拷贝

引用传递:就是引用数据类型的传递,传递是是地址

15、==号和equals的区别

==号:如果比较的是基本类型,那么直接比较值是否相等;如果比较的是引用类型,比较的是引用类型的地址

euqals:比较两个对象,当没有重写equals方法之前,比较的是地址;重写equals方法后,比较的是内容是否相等

16、hashcode

hashcode的作用是获取哈希码(int类型的整数);哈希码的作用是获取对象在hash表中的索引位置,hashcode方法是Object方法,所有的对象都有。

哈希表存储的是key-value形式,所有根据key(索引)可以快速定位到对象

为什么要有hashcode:

以HashSet如何去重为例,HashSet会先计算对象的hash值来判断,如果hash值不同,那么对象就不重复;如果hash值相同,这时还要调用equals方法来判断两个对象的内容是否相同,如果内容相同,则说明是重复的,如果不同,则说明不是重复的。

17、为什么重写equals还要重写hashcode

因为单单只靠euqals不能判断两个对象是否相同

HashMap在put一个键值对时,会先根据键的hashCode和equals方法来同时判断该键在容器中是否已经存在,如果存在则覆盖,反之新建。所以如果我们在重写equals方法时,没有重写hashCode方法,那么hashCode方法还是会默认使用Object提供的原始方法,而Object提供的hashCode方法返回值是不会重复的(也就是说每个对象返回的值都不一样)。所以就会导致每个对象在HashMap中都会是一个新的键。就会有相同的键出现在map集合

18、String、StringBuffer、StringBuilder

String:是一个字符串对象

String str='';//直接创建的放在字符串常量池
String str1=new String();//通过new创建,在堆中产生一个新的对象

String的不可变性:

  • 因为保存字符串的数组被final修饰并且是私有的,string内部也没有暴露访问这个字符串数组的方法
private final cahr value[]
  • string类被final修饰,不能被继承,避免子类破坏的可能性

    StringBuffer和StringBuilder是可变的:

cahr value[]

安全性:

  • String(不可变)和StringBuffer(内部方法是synchronized修饰)是线程安全的
  • StringBuilder是不安全的

19、String为什么要设计成不可变性

  1. 便于实现字符串常量池

在写代码时,会使用大量的字符串,如果每次使用字符串都需要在堆中new一个对象,那么会造成极大的空间浪费,所以java会在堆中开辟一个字符串池,当初始化一个字符串变量时,如果字符串常量池存在相同的变量,就会直接返回已存在对象的引用,不会再创建新的对象。如果字符串是可变的,一旦改变了值,那么指向该对象的引用就会失效了。

  1. 线程安全:因为string是不可变的,其它的线程不能更改,就不会产生线程安全问题
  2. 提高效率

因为String是不可变的,所以它的hashcod是唯一的,在创建对象时可以放心的缓存,不需要重新计算。这也是Map集合喜欢用String来作为键的原因,处理速度更快。

20、包装类型

java为每一个基本类型的数据都引入了包装类型。

基本数据类型 位数 字节 默认值 取值范围 对应的包装类
byte 8 1 0 -128 ~ 127 Byte
short 16 2 0 -32768 ~ 32767 Short
int 32 4 0 -2147483648 ~ 2147483647 Integer
long 64 8 0L -9223372036854775808 ~ 9223372036854775807 Long
char 16 2 'u0000' 0 ~ 65535 Character
float 32 4 0f 1.4E-45 ~ 3.4028235E38 Float
double 64 8 0d 4.9E-324 ~ 1.7976931348623157E308 Double
boolean 1 false true、false Boolean

区别:

  • 包装类型在没有赋值是默认为null,而基本类型都有默认值
  • 包装类型可以用于泛型,基本类型不能
  • 基本类型的局部变量存放在jvm栈帧的局部变量表,成员变量存在在堆中;包装类型是对象类型,存放在堆中

自动装箱:将基本类型转为包装类型

Integer a=10;//声明了一个Integer对象,底层调用Integer.valueOf(10)方法

自动拆箱:将包装类型转为基本类型

Integer a=10;
Sytsem.out.print(a--);//因为对象是不能计算的,使用先转为基本类型再计算

包装类型的缓存机制:

Byte、Short、Integer、Long默认创建了-128127的缓存数据,Character的范围是0127,

Boolean直接返回true、false

image.png

21、反射

指在程序在运行时,动态的获取类和对象的所有属性和方法;动态的获取信息和动态的调用方法

优点:能够动态的获取类的实例,提高灵活性

22、如何获取反射中的class对象

1、在编译阶段,Class.forName("类的路径")

2、类加载阶段:类名.class:一开始就知道要操作的类

3、运行阶段:对象名.getClass

4、如果是包装类型:包装类型.Type

23、反射的API

反射的api用来生成jvm中的类、接口或对象内部信息

Class类:反射的核心,用来获取类的实例

  1. static Class forName(String name) :返回指定类名 name 的 Class 对象
  2. Object newInstance() :调用缺省构造函数,返回该Class对象的一个实例

Field类:表示类的成员变量,可以设置或者获取类变量的值

Field getField(String name):返回此Class对象对应类的指定public Field

Field[] getDeclaredFields() :返回Field对象的一个数组

Method类:表示类的方法,可以获取类的方法信息或者执行方法

  1. Method getMethod(String name,Class … paramTypes) :返回一个Method对象,此对象的形参类型为paramType

Constructor类:表示类的构造方法

通过反射创建对象:

 public static void main(String[] args) throws Exception {
        //1、获取User类的Class对象
        Class<?> cls = Class.forName("Reflect.User");
        //2、通过public的无参构造创建实例
        Object o = cls.newInstance();//User{name = 小葱, age = 20}
        System.out.println(o);

        //3、通过public的有参构造创建实例  constructor对象就是:public User(String name)构造器
        Constructor<?> constructor = cls.getConstructor(String.class);
        Object o1 = constructor.newInstance("小聪");
        System.out.println(o1);//User{name = 小聪, age = 20}

        //通过private的有参构造创建实例
        Constructor<?> constructor1 = cls.getDeclaredConstructor(String.class, int.class);
        //暴破  使得反射可以访问private的构造器
        constructor1.setAccessible(true);
        Object o2 = constructor1.newInstance("小车车", 10);
        System.out.println(o2);//User{name = 小车车, age = 10}
        /*
        getConstructor:返回public的构造器对象
        
			class User{
					private String name="小葱";
					private int age=20;
	
					public User() {
					}
	
					private User(String name, int age) {
						this.name = name;
						this.age = age;
					}
					public User(String name) {
						this.name = name;
	
					}
				}
         */
    }

通过反射获取类的成员:

public class AccessProperty {
    public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("Reflect.Student");
        Object o = cls.newInstance();//o 的运行类型是Student
        //使用反射得到age属性对象
        Field ageField = cls.getField("age");
        ageField.set(o,20);//通过反射来操作属性
        System.out.println(o);//Student{name = null, age = 20}
        System.out.println(ageField.get(o));//返回age属性的值

        //使用反射操作name属性对象
        Field nameField = cls.getDeclaredField("name");
        nameField.setAccessible(true);//可以访问私有
//        nameField.set(o,"小葱");
        nameField.set(null,"小葱");//因为name是static属性,因此 o 也可以写成null
        System.out.println(o);//Student{name = 小葱, age = 20}
    }
}
class Student{
    private static String name;
    public int age;
    public Student(){}

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}

通过反射调用方法:

public class AccessMethod {
    public static void main(String[] args) throws Exception {
        //得到类对象
        Class<?> cls = Class.forName("Reflect.Teacher");
        //创建对象
        Object o = cls.newInstance();
        //根据类的方法名得到方法对象
        Method hi = cls.getMethod("hi", String.class);
        hi.invoke(o,"xiaoc");//hixiaoc

        //私有方法对象
        Method say = cls.getDeclaredMethod("say", String.class, int.class);
        say.setAccessible(true);
        System.out.println(say.invoke(o, "小葱", 20));//小葱 20
        //在反射中 如果方法有返回值 统一返回Object类型
    }
}
class Teacher{
    private String name;
    public int age;

    public Teacher(){}

    private static String say(String str,int n){
        return str+" "+n;
    }
    public void hi(String s){
        System.out.println("hi"+s);
    }
}

24、泛型

将类型参数化,在编译时就确定号具体的参数。可以用在方法、接口和类上,称为泛型接口、泛型方法和泛型类。

核心思想:就是把出现泛型的地方全部替换为传进来的真实类型

好处:

  • 在编译阶段就确定参数的类型,从而不会出现类型转换异常
  • 消除了强制类型转换,使用泛型可以直接得到目标类型。

25、序列化与反序列化

序列化:把java对象转为字节序列(二进制流)的过程,以便在网络上传输或者保存在本地。

反序列化:把字节序列转为java对象的过程。

java对象是存储在jvm堆中的,如果jvm堆不存在了,那么java对象也消失了。所以使用序列化将对象保存在本地,需要时又从本地读取。

26、序列化实现方式

类必须实现如下两个接口之一,才能让类是可序列化的:

1、Serializable//这是一个标记接口 没有方法(常用)

2、Externalizable //需要实现方法

使用ObjectOutputStream

public static void main(String[] args) throws Exception {
        /*
            1、使用ObjectOutputStream 序列化 基本数据类型和一个Dog对象(name,age)并保存
         */
        String filePath="C:\\Users\\xiaocong\\Desktop\\b.txt";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));

        //序列化数据到 filePath
        oos.write(100);//int-->Integer(实现类序列化接口) 自动转换为包装类型
        oos.writeUTF("hello");//String
        //保存一个dog对象
        oos.writeObject(new Dog("大黄",10));
        oos.close();
    }

jvm在序列化时,会自动生成一个SerialVersionUID,然后与属性一起序列化,再进行持久化或网络传输。在反序列化时,jvm会再生成一个新的SerialVersionUID,然后将两个SerialVersionUID比较,如果相同,则反序列化成功,否则会报错。

如果显示指定了SerialVersionUID,jvm在创建SerialVersionUID时值是我们指定的。

如果不指定,会有什么问题?

如果我们写完类就不再修改,那就不会有问题。在实际开发中,类是不断迭代的,一旦类修改了,那么旧对象的反序列化就会失败。

如果有些字段不需要进行序列化,可以使用transient修饰。

静态变量不会被序列化,因为序列化是针对对象的,静态变量优先于对象创建

27、Error和Exception

在java中,所有异常都有一个共同的祖先,java.lang包下的Throwable类。Throwable有两个重要的子类,Exception(异常)和Error(错误)

image.png

Exception:程序本身可以处理的异常,可以通过try catch来捕获。

  • 异常由分为运行时异常和非运行时异常

运行时异常:又叫非受检查异常,表示在运行期间可能出现的异常,在编译阶段不会检查。

如:空指针异常、数组索引越界异常、算术错误异常、类转换异常

非运行时异常:又叫受检查异常,表示在编译期间就可以检查的异常

比如:类找不到异常、SQL异常

Error:属性程序无法处理的错误,一旦这类错误发生,程序会被终止。

声明异常:throws 作用在方法上,可以抛出多个异常

抛出异常:throw 用在方法内部,只能抛出一种异常。throw new 异常类型();

28、jvm是如何处理异常的

如果在一个方法中发生了异常,这个方法会创建一个异常对象,并传给jvm,该异常对象包含异常名,异常描述以及异常发生时应用程序的状态。可以有一系列方法的调用,最终才进入异常方法,这一系列方法会形成一个调用栈,jvm会顺着调用栈来查看是否有可以处理异常的代码,如果有,则调用异常处理代码。如果没有,jvm会在控制台打印出异常信息。

29、字节流如何转换为字符流

字节输入流转为字符输入流:InputStreamReader(解决字节流读取乱码的问题)

方法:public InputStreamReader(InputStream in, Charset cs) :指定编码方式

 public static void main(String[] args) throws IOException {
        String filePath="要读取的文件路径";
        //1、把FileInputStream  转为  InputStreamReader  并且指定编码
        InputStreamReader isr=new InputStreamReader(new FileInputStream(filePath), "GBK");
        //2、把  InputStreamReader 传入 BufferedReader
        BufferedReader br = new BufferedReader(isr);
        String s = br.readLine();
        System.out.println(s);
        //关闭外层流
        br.close();
    }

字节输出流转为为字符输出流:OutputStreamWriter

方法:public OutputStreamWriter(OutputStream out, String charsetName)

public static void main(String[] args) throws IOException {
        String fileName="要写入的文件路径";
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream(fileName),"gbk");
        BufferedWriter bw = new BufferedWriter(osw);
        bw.write("hello,world");
    }

30、什么是阻塞IO,非阻塞IO?

IO操作包括:对硬盘的读写,对socket读写以及外设的读写

当用户线程发起一个IO请求,操作系统会去查看要读取的数据是否准备就绪

  • 对于阻塞IO:如果数据没有准备就绪,则会一直等待,直到数据就绪
  • 对于非阻塞IO:如果数据没有就绪,则会返回一个标志信息告知用户线程当前要读的数据没有就绪。当数据就绪后,便将数据拷贝到用户线程。

31、BIO、NIO、AIO

BIO:

同步并阻塞,在服务器中的实现是一个连接一个线程。当有连接请求的时候,服务器会启动一个线程处理。如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。

NIO:

同步并非阻塞,实现方式是一个请求一个线程,客户端发来的请求都会注册到多路复用器上,多路复用器查询到有连接IO请求时才会启动一个线程进行处理。(I/O多路复用通过一种机制,可以监视多个描述符,一旦某个描述符就绪,能够通知相应的进程/线程进行相应操作)

AIO:

异步并非阻塞,实现方式是一个有效请求一个线程,客户端的请求都是在操作系统完成之后,再通知服务器去启动线程处理。

标签:String,对象,javase,序列化,方法,public,name
来源: https://www.cnblogs.com/XIAOC521/p/16564132.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有