java学习-day04

个人曾经学习java的一些记录,仅供参考

Static关键字

static可以用来修饰属性和方法

static修饰的属性我们叫做静态变量、类变量

static修饰的方法我们叫做静态方法、类方法

static修饰的属性和方法不需要通过对象了调用,直接通过类名调用即可(推荐使用类名调用)

static修饰的属性存在方法区,他不属于任何对象,所以不在堆空间。

public class User {

   static String USERNAME;

   static int NUMBER = 100;

   int count = 100;

   static void show(){
      System.out.println("User is show");
   }

}

调用

public class Test {
   public static void main(String[] args) {
      //System.out.println(User.USERNAME);
      //User.show();

      User u1 = new User();
      System.out.println("U1 NUMBER:" + u1.NUMBER);// 100
      System.out.println("U1 COUNT:"+ u1.count);// 100
      User u2 = new User();
      u2.NUMBER = 90;
      u2.count = 90;
      System.out.println("U1 NUMBER:" + u1.NUMBER);// 90
      System.out.println("U1 COUNT:" + u1.count);// 100

   }
}

总结:

static修饰的变量叫做类变量,可以直接通过类调用,也可以通过对象调用,当其中一个对象对类变量进行改变后,那么其他对象来访问这个类变量的时候也会受到影响,而成员变量属性成员私有的,每个对象在堆空间都有一个独立的存储空间,对象只能修改自己的成员变量。

内存图:

在这里插入图片描述

创建对象JVM做了什么事情

1、加载类,同时初始化所有static修饰的属性和方法。按照顺序执行

2、初始化所有的成员属性和方法,按照顺序执行

3、通过new调用构造方法

public class Test {
   int count;//成员变量
   {
      System.out.println("block 1");
   }
   {
      System.out.println("block 2");
   }
   static {
      System.out.println("static block 1:" + Test.NUM);
   }
   static int NUM = 10;//类变量
   static {
      System.out.println("static block 2:" + NUM);

   }
   public Test() {
      System.out.println("Test is init");
   }
   public static void main(String[] args)throws Exception {
      //System.out.println(Test.NUM);
      //  加载类 : 初始化所有的static修饰的属性和方法
      Class.forName("com.iweb.java05.Test");
   }
}

静态方法

静态方法中只能直接调用静态属性和静态方法,静态方法中没有this

public class Test {
   
   static int NUMBER = 100;
   
   String str = "abc";
   
   public static void show(){
      System.out.println(NUMBER);
      //System.out.println(str);
   }

   public static void main(String[] args) {
      show();
   }
   
}

内部类

声明在类中的类的叫做内部类,内部类我们可以分为:1、普通内部类 2、局部内部类 3、静态内部类 4、匿名内部类。 同时内部类也是一种多态!

/**
 * 外部类
 */
public class Outer {

   /**
    * 外部类的方法
    */
   public void out(){
      System.out.println("Outer is out");
   }

   /**
    * 内部类
    */
   class Inner extends Father{
      public void fn(){
         show(); // 调用的是Father的方法
         out(); //调用的Outer外部类的方法
      }
   }
}

由以上的例子我们可以看出,内部类也是一种多态,因为一个类只能直接继承一个父类,很多场景我们无法实现,可以通过内部类的方式来实现,内部类也是外部类的一种扩展。

内部类的特征

我们通过一个普通内部类来进行观察:

package com.iweb.java02;
/**
 * 外部类
 */
public class Outer {

   public static int NUMBER  = 100;
   private String username = "jack";
   private String password = "123456";

   /**
    * 外部类的方法
    */
   public void out(){
      System.out.println("Outer is out");
   }

   public static void staticOut(){
      System.out.println("Outer is static out");
   }

   /**
    * 内部类
    */
   class Inner{

      private String username = "inner jack";
      //不能拥有 static 修饰的属性和方法
//      public static int NUMBER = 200;
      public void fn(){
         out(); //调用的Outer外部类的方法
         System.out.println(username);// inner jack
         System.out.println(Outer.this.username);// jack
         System.out.println(password); // 123456
         System.out.println(NUMBER); // 100
         staticOut();
      }
//      public static void staticInner(){}
   }
}

调用

package com.iweb.java02;

public class Test {
   public static void main(String[] args) {
      //如何调用内部类的属性和方法
      Outer outer  = new Outer();
      //通过外部类的对象去创建内部类的对象
      Outer.Inner oi = outer.new Inner();
      oi.fn();//调用内部类的方法
   }
}

总结:

1、内部类可以直接访问外部类的属性和方法(包含私有);

2、内部类不能由static修饰的属性和方法。

3、可以通过创建外部类的对象来创建内部类的对象,访问内部类的属性和方法

局部内部类

定义:声明在方法中类,叫做局部内部类

public class Outer {
   public void show(){
      // 局部内部类 : 顺序执行
      class Inner{
         public void inner(){
            System.out.println("Inner is inner");
         }
      }
      Inner inner = new Inner();
      inner.inner();
   }

   public static void main(String[] args) {

      Outer outer = new Outer();
      outer.show();

   }
}

总结:

1、局部内部类中不能有static修饰的属性和方法

2、局部内部类的作用域不能超出声明这个类的方法,只能在当前方法中被调用

3、只能通过调用该内部类所在的方法来调用局部内部类

4、局部内部类在方法中是顺序执行的。

静态内部类

static修饰的内部类

public class Outer {

   static int NUMBER = 100;

   static class Inner{

      static String USERNAME = "jack";

      public static void show(){
         System.out.println(NUMBER);
      }
      //可以通过创建对象来访问run
      public void run(){
         System.out.println(NUMBER);
      }

   }
}

调用

public class Test {
   public static void main(String[] args) {
      //调用静态内部类的属性
      System.out.println(Outer.Inner.USERNAME);
      Outer.Inner.show();
      //访问内部类的成员方法
      Outer.Inner oi = new Outer.Inner();
      oi.run();
   }
}

匿名内部类

没有类的名称的内部类:可以理解为方法重写

public abstract class Outer {
   public abstract void show();
}
public class Test {
   public static void main(String[] args) {
      //内部类
      Outer outer = new Outer() {
         public void show() {
            System.out.println("inner is show");
         }
      };
      // 需要定义外部类(父类,子类就是这个内部类,只是没有名字)的接口,可以理解为是方法重写
      outer.show();
   }
}
public class Test {
   public static void main(String[] args) {
      //内部类
      Outer outer = new Outer() {
         public void show() {
            System.out.println("inner is show");
         }
      };
      // 需要定义外部类(父类,子类就是这个内部类,只是没有名字)的接口,可以理解为是方法重写
      outer.show();
   }
}

包的创建:package com.dst.java04;

包的作用: 工程管理

包名全部小写

包的引用:import java.utils.*;

Java中常见的包:

java.lang: 这个包下的所有的类的引用无需引用,可以直接使用。String , 包装类

java .uitl: 工具包

java.sql : 数据库操作

java.net : 网络

java.io : 数据流 File

接口

我们可以通过内部类进行功能的扩展,可以通过继承进行功能的扩展。很多常见还是不能实现。 JDK提供了接口。

java继承是单继承,接口可以多实现,也就是一个子类可以有多个父接口。

接口也是一个class,是一个特殊的class,在编译的时候也会被编译成 .class文件

接口的特性

特征一:属性和方法

1、所有属性都是常量

2、所有方法都是抽象方法

3、接口没有构造函数,接口不能实例化,必须通过子类进行实例化

4、接口可以多实现

public interface User {
   
   // 所有的变量都是 public final static 必须给定初始值 ,可以省略不写 编码规范必须不写
   public final static int NUMBER = 100;
   // 所有的方法都是 public abstract ,可以省略不写  编码规范必须不写
   public abstract void show();
   
}

子类的实现

public class UserImp implements User {
   @Override
   public void show() {
      System.out.println("User imp show");
   }
}

测试

public class Test {

   public static void main(String[] args) {
      // 不能直接实例化,必须通过子类进行实例化
      User user = new UserImp();
      user.show();
   }
}

特征二:接口和接口、抽象类、普通类直接的关系

1、接口可以继承接口

2、抽象类可以实现接口,可以重写接口中的抽象方法,也可以补充些(因为抽象类支持抽象方法)

3、普通类可以实现接口,一个类如果实现了接口必须重写所有父接口中的所有抽象方法

interface I {
   void show_i();
}

interface G {
   void show_g();
}

abstract class F {

}

class C extends F implements I, G {

   @Override
   public void show_i() {
   }

   @Override
   public void show_g() {
   }
}

总结:一个类可以继承一个类的同时实现多个接口

public class Test {
}
interface I{
   void show();
}

interface G extends I{

}
class C implements G{

   @Override
   public void show() {
      
   }
}

总结:接口可以接触接口,一个类实现了一个接口,必须重写所有父接口中的所有抽象方法

public class Test {

}
interface I{

   void show();
   
   void run();
}
abstract class F implements I{
   @Override
   public void show() {
      
   }
}
class C extends F{

   @Override
   public void run() {
      
   }
}

总结:抽象类可以接触接口,可以实现接口中的抽象方法,也可以不重写。

什么时候使用接口

一句话: 能用接口就用接口,接口是设计的结构。

一般的设计3层 : 接口 =>抽象类=>业务类

例子:通过程序访问数据库

分析:数据库可能存在数据库移植,本来使用的是Oracle 通过数据库移植使用了MySQL ,或者说一个业务可能使用到多个数据库。

数据库的操作 简单分为三部 : 连接、操作、关闭
在这里插入图片描述

DataBase.java

public interface DataBase {

   //Oracle的连接 和 MySQL的连接: 参数不同 url username password
   void connect();

   void connect(String url,String username,String password);

   void select();

   void close();

}

AbstractDataBase.java

public abstract class AbstractDataBase  implements DataBase{
   private String url;
   private String username;
   private String password;

   public void set(String url,String username,String password){
      System.out.println("set parms");
      this.url = url;
      this.username = username;
      this.password = password;
   }

   @Override
   public void close() {
      System.out.println("数据库关闭");
   }

}

MySqlDataBase.java

public class MySqlDataBase extends AbstractDataBase implements DataBase {

   @Override
   public void connect() {
      //设置的是mysql的数据
      set("jdbc:mysql://localhost:3306/test","root","123456");
      System.out.println("Oracle is connect");
   }

   @Override
   public void connect(String url, String username, String password) {
      set(url,username,password);
   }

   @Override
   public void select() {
      System.out.println("MySQL is select");
   }


}

OracleDataBase.java

public class OracleDataBase extends AbstractDataBase implements DataBase {
   @Override
   public void connect() {
      set("jdbc:oracle:thin:localhost:1521:test","scott","123456");
      System.out.println("Oracle is connect");
   }

   @Override
   public void connect(String url, String username, String password) {
      set(url,username,password);
   }

   @Override
   public void select() {
      System.out.println("Oracle is select");
   }


}

Test.java

public class Test {
   public static void main(String[] args) {
      DataBase db = new OracleDataBase();
      db.connect();
      db.select();
      db.close();
   }
}

接口和抽象类的区别:

1、抽象类和接口都不能直接实例化,如果要实例化, 只能通过子类进行实例化。
2、抽象类要被子类继承,接口要被类实现。
3、接口所有的方法都是抽象方法,抽象类中可以可以有抽象方法也可以有实例方法。
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,
一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能声明,不能实现,接口是设计的结果 ,抽象类是重构的结果
7、抽象类里可以没有抽象方法
8、抽象方法要被实现,所以不能是静态的,也不能是私有的。
9、接口可继承接口,并可多实现接口,但抽象类只能单根继承。

访问控制符

访问权限:4个

分别是:public 、缺省的、protected、private

public :可以修饰类、属性、方法。修饰的类、属性和方法任何位置都可以访问

protected: 可以修饰 属性和方法,不可以修饰类。修饰的属性和方法,可以在同包、不同包的子类、类中访问

缺省的:不是default,可以修饰类、属性和方法。是什么都不写(int i =100;) int前面没有修饰符 。同包中,同类中可以访问。

private:私有的,可以修饰属性和方法,不能修饰类。只有类中可以访问

final

1、可以修饰类、属性、方法

2、修饰的类是最终类。不能被继承

3、修饰的属性必须有初值,值不可变

4、修饰的方法不能被重写

异常

什么是异常

异常库

在这里插入图片描述

异常分类

运行时异常:RuntimeException和它的子类

检查异常:非RuntimeException和它子类统称为检查异常

如何处理异常

public class Test {
   public static void main(String[] args) {

      // 运行时异常
//      int[] arr = {1,2,3};
//      System.out.println(arr[3]);
//      System.out.println(1/0);
//      String str = null;
//      str.equals("");

      // 检查异常
      File file = new File("E:\\a.txt");

      try {
         FileReader reader = new FileReader(file);
      }catch (FileNotFoundException e){
         e.printStackTrace();//异常的追踪
      }


   }
}

总结:

运行时异常不需要程序员显示的处理,当发生异常的时候交由JVM处理。 而检查异常,则需要程序员显示的处理。

处理方式

捕获:通过try … catch 块进行处理 ,在try块中编写可能发生异常的代码,而在catch块中打印异常追踪的接结果。捕获是一种积极的处理方式。

try … catch 可以有多个catch块,当发生异常的时候JVM会根据异常的类型决定进入哪一个catch块

public class Test {

   public void printArr(int[] arr){
      try {
         //  有可能发生异常
         System.out.println(arr[1]);
         System.out.println("打印数组");
         System.out.println(arr[0]/1);
         System.out.println("计算结果");
      }catch (ArrayIndexOutOfBoundsException e){
         System.out.println("数组越界");
         //e.printStackTrace();  // 打印异常跟踪的结果
         //System.out.println(e.getMessage()); // 打印异常的信息
      }catch (ArithmeticException e){
         System.out.println("算数异常");
      }finally {
         // 无论异常是否发生都会执行:一般用于数据库关闭
         // 在数据库操作的过程中可能会发生异常,如果不关闭数据库,那么连接可能被阻塞
         System.out.println("finally");
      }
   }
   public static void main(String[] args) {

      Test t = new Test();
      t.printArr(new int[]{1,2});

   }
}

抛出:在可能发生异常的方法后使用throws关键字抛出异常,将异常的处理交给方法的调用者。是一种消极的处理方式

public class Test {

   public void op(int num) throws ArithmeticException{
//      try {
//         System.out.println(1 / num);
//      }catch (ArithmeticException e){
//         System.out.println(e.getMessage()+"....");
//      }
      System.out.println(1 / num);
   }

   public static void main(String[] args) {
      Test t = new Test();
//      try {
//         t.op(0);
//      }catch (ArithmeticException e){
//         System.out.println(e.getMessage());
//      }
      t.op(0);
   }
}

演示检查异常

public class Test {
   public void readFile(String path)throws  Exception {
         FileReader reader = new FileReader(path);

         System.out.println("文件读取完毕:"+reader.read());
   }

   public static void main(String[] args) {
      Test t = new Test();
      try {
         t.readFile("D:\\workspace\\XZ223\\day07\\src\\com\\iweb\\java20\\a.txt");
      } catch (Exception e) {
         e.printStackTrace();
      }
   }
}

总结:

1、可以通过抛出或者捕获异常的父类,这样可以省去写很多catch代码比较整洁

2、什么时候使用try … catch 什么时候使用 throws ,当异常发生后还需要有业务处理的时候那么就用try …catch,比如说:数据库连接,文件读取。如果不需要那么都可以抛出

3、捕获和抛出都是都不是解决异常的根本方法,只是告诫程序员发生了什么异常。帮助程序员进行异常的定位。

如何解决异常

1、根据异常的错误类查找API ,

2、API会提供异常发生的可能性

3、解决问题

自定义异常

模仿JDK的写法: NullPointerException

定义一个类继承:RuntimeException

/**
 * 人妖re
 * 当异常发生时候,调用者可能输入了 "人妖"
 */
public class MyException extends RuntimeException {

   public MyException() {
   }

   public MyException(String message) {
      super(message);
   }
}

使用自定义异常

public class Test {

   /**
    * 不允许用户传入 "人妖"
    * @param name
    */
   public void printPerson(String name){
      if(name.equals("人妖")){
         throw new MyException();
      }
      System.out.println(name);
   }
   public static void main(String[] args) {
      Test t = new Test();
      t.printPerson("人妖");
   }
}

基本数据类型和包装类

基本数据类型:是java中的类型,只能用来定义、声明某一个数据类型,没有操作方法

包装类:每个基本数据类型都对应着一个包装类,是一个引用数据类型。提供了操作方法

为什么要用包装类:因为基本数据类型只是类型的声明,没有对数据的操作方法。而包装类提供了对该类型的操作方法。

int

public class Test {

   public static void main(String[] args) {

      //如果希望将一个int类型转成String类型,而int并没有API可以进行操作
      //Integer 提供了 toString 可以将int型转成String
      int i = 10; // Integer
      Integer in = new Integer(10);
      System.out.println(in.toString()+10);

      byte b = 10;
      Byte bt = new Byte((byte) 10);
      System.out.println(bt.toString()+20);

   }

}

基本数据类型和包装类的对应关系

byte = Byte

short = Short

int = Integer

long = Long

float = Float

double = Double

boolean = Boolean

char = Character

自动装箱和自动拆箱

public class Test {

   public static void main(String[] args) {
      // 引用数据类型:
      Integer a = 10;
      Integer b = 20; //自动装箱
      // JVM会帮助我们将a和b转成int型 : 自动拆箱
      System.out.println(a+b);
   }

}

反编译结果
在这里插入图片描述

强化记忆:

装箱: 由字面量到引用数据类型的时候叫做自动装箱,可以把堆理解为是那个箱子

拆箱:当数据用于计算的时候就会拆箱,要从堆中将数据取出进行运算

基本数据类型和包装类的比较

public class Test {

   public static void main(String[] args) {
      // 引用数据类型:
//      byte a = 10;
//      byte b = 10;
//      Byte c = 10;
//      Byte d = 10;
//      System.out.println(a == b);//true
//      System.out.println(a == c);//true
//      System.out.println(c == d);//true

//      int a = 200;
//      int b = 200;
//      Integer c = 200; // -128  127 会到常量池中取得数据 而超出这个范围的数据 需要重新生成对象
//      Integer d = 200;
//      System.out.println(a == b);//true
//      System.out.println(a == c);//true
//      System.out.println(c == d);//false

      // 浮点型不进行数据区间的认证,直接new出来的所有不存在-128 到127之间的区别
      float a = 100f;
      float b = 100f;
      Float c = 100f;
      Float d = 100f;
      System.out.println(a == b);//true
      System.out.println(a == c);//true
      System.out.println(c == d);//false

   }

}

什么时候使用基本数据类型和引用数据类型

1、当这个数据用于比较运算的时候尽量使用基本数据类型

2、但用基本数据类型的缺省值存在意义的时候,使用引用数据类型

BigDecimal

public class Test {
   public static void main(String[] args) {

      long l = Long.MAX_VALUE+200;
      System.out.println(l);
      BigDecimal a = new BigDecimal(Long.MAX_VALUE);
      BigDecimal b = new BigDecimal(200);
      System.out.println(a.add(b));

   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值