Wednesday, March 6, 2019

Android开发笔记-ch2 Java


2.1 Core Java

2.1.1 CharSequence vs. String

Strings are CharSequences, so you can just use Strings and not worry. Android is merely trying to be helpful by allowing you to also specify other CharSequence objects, like StringBuffers.

2.1.2 Compare Strings

Refer to this SO. == operator is not good for comparing strings. == tests for reference equality (whether they are the same object). .equals() tests for value equality. Objects.equals() checks for nulls before calling .equals().
// These two have the same value
new String("test").equals("test") // --> true

// but they are not the same object
new String("test") == "test" // --> false

// neither are these
new String("test") == new String("test") // --> false

// but these are because literals are interned by the compiler and thus refer to the same object
"test" == "test" // --> true

// checks for nulls and calls .equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Note null and “” is not same thing. Refer to this SO: Check empty String with if (s == null || s.isEmpty()) or "".equals(s).
The main benefit of "".equals(s) is you don't need the null check (equals will check its argument and return false if it's null).

2.1.3 Nested classes

Refer to this SO and Oracle: Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes. A nested class is a member of its enclosing class. Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private. Static nested classes do not have access to other members of the enclosing class. As a member of the OuterClass, a nested class can be declared private, public, protected, or package private. For anonymous inner class, refer to oracle and SO.

2.1.4 local variable accessed by inner class needs to be declared as final

I have code as below and as explained in SO, Anonymous inner classes have access to local variables through a trick behind the scenes. Local variable are implemented as hidden member variables of the inner class. They are assigned copies of the local variable. To prevent the copy value from being wrong, the Java compiler enforces that these local variables must be final so they aren't changed, so the copy stays correct. Below is my code, where the adapter is a local vairable and is referenced in the inner class:
final ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
...
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(mTabLayout) {
...
    @Override
    public void onPageSelected(int position) {
        ((MyMplFragment) adapter.getItem(position)).mTv.setText("this is " + position);
    }

2.1.5 Virtual function

According to wikipedia: The concept of the virtual function solves the following problem: In object-oriented programming, when a derived class inherits from a base class, an object of the derived class may be referred to via a pointer or reference of the base class type instead of the derived class type. If there are base class methods overridden by the derived class, the method actually called by such a reference or pointer can be bound either 'early' (by the compiler), according to the declared type of the pointer or reference, or 'late' (i.e., by the runtime system of the language), according to the actual type of the object referred to. Virtual functions are resolved 'late'. If the function in question is 'virtual' in the base class, the most-derived class's implementation of the function is called according to the actual type of the object referred to, regardless of the declared type of the pointer or reference. If it is not 'virtual', the method is resolved 'early' and the function called is selected according to the declared type of the pointer or reference. Virtual functions allow a program to call methods that don't necessarily even exist at the moment the code is compiled. In C++, virtual methods are declared by prepending the virtual keyword to the function's declaration in the base class. This modifier is inherited by all implementations of that method in derived classes, meaning that they can continue to over-ride each other and be late-bound.
A pure virtual function or pure virtual method is a virtual function that is required to be implemented by a derived class if the derived class is not abstract. Classes containing pure virtual methods are termed "abstract" and they cannot be instantiated directly. A subclass of an abstract class can only be instantiated directly if all inherited pure virtual methods have been implemented by that class or a parent class. Pure virtual methods typically have a declaration (signature) and no definition (implementation).
It is recommended that virtual function calls in constructors should be avoided for C++.
In Java, all non-static methods are by default "virtual functions." Only methods marked with the keyword final, which cannot be overridden, along with private methods, which are not inherited, are non-virtual.

2.1.6 Java data structure

String, Hashtable, HashMap(The HashMap class is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls, refer to this SO), ArrayList, Collections(note: Collection is an terface, same for Map, Set, and Serializable/Cloneable/Iterable).
Here is examples of 3 ways to access ArrayList:
for (int i = 0; i < list.size(); i++) {System.out.println("Index: " + i + " - Item: " + list.get(i));}
for (String str : list) {System.out.println("Item is: " + str);}
for (Iterator<String> it = list.iterator(); it.hasNext()) {System.out.println("Item is: " +it.next());}

2.1.7 Enhance for loop

Refer to this for loop through an array(numbers is an Int array):
for (int item : numbers) { System.out.println("Count is: " + item); }

2.1.8 BufferReader vs. InputStreamReader vs. FileReader

An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted. InputStreamReader can read any stream, include FileInputStream, socket, HTTP connection, or database blob; FileReader can only read file, and is using default character encoding, which could be wrong if the file is using a different char encoding. BufferReader Reads text from a character-input stream, buffering characters so as to provide for the efficient reading of characters, arrays, and lines. So it can be chained with either a FileReader or an InputStreamReader like this: BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("filename"))));
or BufferedReader br = new BufferedReader(new FileReader(new File("filename")));
Refer this SO for converting a String to a InputStream, i.e:
InputStream stream = new ByteArrayInputStream(exampleString.getBytes(StandardCharsets.UTF_8));
Refer this SO for reading file to byte[]: IOUtils.toByteArray(InputStream input); =>need Jar of commons.apache.org commons-io
Or using java.io (good for Android, w/o need of extra jar):
RandomAccessFile f = new RandomAccessFile(fileName, "r");
byte[] b = new byte[(int)f.length()];
f.read(b);
Or for using JDK7(not good for Android):
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
Path path = Paths.get("path/to/file");
byte[] data = Files.readAllBytes(path);
For read InputStream to String, refer to this SO for 11 ways to do that.

2.1.9 Throwable

Refer to this SO, and this SO and this SO. By catching Throwable it includes things of subclass Error. You should generally not do that, except perhaps at the very highest "catch all" level of a thread where you want to log or otherwise handle absolutely everything that can go wrong. It would be more typical in a framework type application (for example an application server or a testing framework) where it can be running unknown code and should not be affected by anything that goes wrong with that code, as much as possible.
Throwable includes Exception and Error. Error is programmatically unrecoverable in any way and is usually not to be caught, except for logging purposes (which passes it through again). Exception is programmatically recoverable. Its subclass RuntimeException indicates a programming error and is usually not to be caught as well.
Thowable catches really everything even ThreadDeath which gets thrown by default to stop a thread from the now deprecated Thread.stop() method. So by catching Throwable you can be sure that you'll never leave the try block without at least going through your catch block, but you should be prepared to also handle OutOfMemoryError and InternalError or StackOverflowError.
Catching Throwable is most usefull for outer server loops that delegate all sorts of requests to outside code but may itself never terminate to keep the service alive.
Throwable is super class of Exception as well as Error. In normal cases we should always catch sub-classes of Exception, so that the root cause doesn't get lost.
Only special cases where you see possibility of things going wrong which is not in control of your Java code, you should catch Error or Throwable. I remember catching Throwable to flag that a native library is not loaded.

2.1.10 Runnable

A Runnable is basically a type of class (Runnable is an Interface) that can be put into a thread, describing what the thread is supposed to do. The Runnable Interface requires of the class to implement the method run() like so:
public class MyRunnableTask implements Runnable {
public void run() {
// do stuff here
}
}
And then use it like this:
Thread t = new Thread(new MyRunnableTask());
t.start();
If you did not have the Runnable interface, the Thread class, which is responsible to execute your stuff in the other thread, would not have the promise to find a run() method in your class, so you could get errors. That is why you need to implement the interface.

Advanced: Anonymous Type

Note that you do not need to define a class as usual, you can do all of that inline:
Thread t = new Thread(new Runnable() {
public void run() {
// stuff here
}
});
t.start();
This is similar to the above, only you don't create another named class.

2.1.11 String, StringBuffer, StringBuilder

Refer to SO and this. String is immutable ( once created can not be changed )object. The object created as a String is stored in the Constant String Pool. StringBuffer is synchronized and thread safe, StringBuilder is not synchronized and is not thread safe. So StringBuilder is faster than StringBuffer.

2.1.12 Reference

Refer to SO. Java Spec says that everything in Java is pass-by-value. But all declared variable is a reference of the type.

2.1.13 Access



Class
Package
Subclass(same pkg)
Subclass(diff pkg)
World
Public
+
+
+
+
+
Protected
+
+
+
+
O
No modifier(default)
+
+
+
O
O
Private
+
O
O
O
O
+ : accessible
o : not accessible


2.2 Graphics/UI


2.3 Regex

Refer to String.replaceAll and Java regex.
 

0 Comments:

Post a Comment