Wiem, że Java nie ma wskaźników, ale słyszałem, że programy Java można tworzyć za pomocą wskaźników i że mogą to zrobić nieliczni eksperci w Javie. Czy to prawda?
Wiem, że Java nie ma wskaźników, ale słyszałem, że programy Java można tworzyć za pomocą wskaźników i że mogą to zrobić nieliczni eksperci w Javie. Czy to prawda?
Odpowiedzi:
Wszystkie obiekty w Javie są odniesieniami i można ich używać jak wskaźników.
abstract class Animal
{...
}
class Lion extends Animal
{...
}
class Tiger extends Animal
{
public Tiger() {...}
public void growl(){...}
}
Tiger first = null;
Tiger second = new Tiger();
Tiger third;
Dereferencing a null:
first.growl(); // ERROR, first is null.
third.growl(); // ERROR, third has not been initialized.
Problem z aliasingiem:
third = new Tiger();
first = third;
Utrata komórek:
second = third; // Possible ERROR. The old value of second is lost.
Możesz to zabezpieczyć, upewniając się najpierw, że nie ma już potrzeby stosowania starej wartości sekundy lub przypisując innemu wskaźnikowi wartość sekundy.
first = second;
second = third; //OK
Zauważ, że nadanie drugiemu wartości w inny sposób (NULL, nowy ...) jest równie potencjalnym błędem i może spowodować utratę obiektu, na który wskazuje.
System Java zgłosi wyjątek ( OutOfMemoryError
), gdy wywołasz new i alokator nie może przydzielić żądanej komórki. Jest to bardzo rzadkie i zwykle wynika z rekursji ucieczki.
Zauważ, że z punktu widzenia języka, porzucanie obiektów do garbage collectora wcale nie jest błędem. To jest coś, o czym programista musi być świadomy. Ta sama zmienna może wskazywać na różne obiekty w różnym czasie, a stare wartości zostaną odzyskane, gdy żaden wskaźnik nie będzie do nich odwoływał. Ale jeśli logika programu wymaga utrzymywania co najmniej jednego odwołania do obiektu, spowoduje to błąd.
Nowicjusze często popełniają następujący błąd.
Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed.
Prawdopodobnie chciałeś powiedzieć:
Tiger tony = null;
tony = third; // OK.
Niewłaściwe przesyłanie:
Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler.
Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.
Wskaźniki w C:
void main() {
int* x; // Allocate the pointers x and y
int* y; // (but not the pointees)
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
*y = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
*y = 13; // Dereference y to store 13 in its (shared) pointee
}
Wskaźniki w Javie:
class IntObj {
public int value;
}
public class Binky() {
public static void main(String[] args) {
IntObj x; // Allocate the pointers x and y
IntObj y; // (but not the IntObj pointees)
x = new IntObj(); // Allocate an IntObj pointee
// and set x to point to it
x.value = 42; // Dereference x to store 42 in its pointee
y.value = 13; // CRASH -- y does not have a pointee yet
y = x; // Pointer assignment sets y to point to x's pointee
y.value = 13; // Deference y to store 13 in its (shared) pointee
}
}
AKTUALIZACJA: zgodnie z sugestią w komentarzach należy zauważyć, że C ma arytmetykę wskaźnikową. Jednak nie mamy tego w Javie.
Java ma wskaźniki. Za każdym razem, gdy tworzysz obiekt w Javie, w rzeczywistości tworzysz wskaźnik do obiektu; ten wskaźnik może być wtedy ustawiony na inny obiekt lub na null
, a oryginalny obiekt będzie nadal istniał (w oczekiwaniu na czyszczenie pamięci).
To, czego nie można zrobić w Javie, to arytmetyka wskaźników. Nie można wyłuskać konkretnego adresu pamięci ani zwiększyć wskaźnika.
Jeśli naprawdę chcesz uzyskać niski poziom, jedynym sposobem na to jest użycie natywnego interfejsu Java ; a nawet wtedy część niskopoziomowa musi być wykonana w C lub C ++.
Ponieważ Java nie ma typów danych wskaźników, nie można używać wskaźników w Javie. Nawet nieliczni eksperci nie będą w stanie używać wskaźników w java.
Zobacz także ostatni punkt w: Środowisko języka Java
W Javie są wskaźniki, ale nie można nimi manipulować tak, jak w C ++ lub C. Przekazując obiekt, przekazujesz wskaźnik do tego obiektu, ale nie w takim samym sensie, jak w C ++. Nie można usunąć odwołania do tego obiektu. Jeśli ustawisz jego wartości za pomocą natywnych metod dostępu, zmieni się, ponieważ Java zna swoją lokalizację w pamięci za pomocą wskaźnika. Ale wskaźnik jest niezmienny. Kiedy próbujesz ustawić wskaźnik w nowej lokalizacji, zamiast tego otrzymujesz nowy obiekt lokalny o tej samej nazwie co drugi. Oryginalny obiekt pozostaje niezmieniony. Oto krótki program pokazujący różnicę.
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone {
public static void main(String[] args) throws java.lang.Exception {
System.out.println("Expected # = 0 1 2 2 1");
Cat c = new Cat();
c.setClaws(0);
System.out.println("Initial value is " + c.getClaws());
// prints 0 obviously
clawsAreOne(c);
System.out.println("Accessor changes value to " + c.getClaws());
// prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
makeNewCat(c);
System.out.println("Final value is " + c.getClaws());
// prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
}
public static void clawsAreOne(Cat kitty) {
kitty.setClaws(1);
}
public static void makeNewCat(Cat kitty) {
Cat kitten = new Cat();
kitten.setClaws(2);
kitty = kitten;
System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
//Prints 2. the value pointed to by 'kitten' is 2
System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
//Prints 2. The local copy is being used within the scope of this method.
}
}
class Cat {
private int claws;
public void setClaws(int i) {
claws = i;
}
public int getClaws() {
return claws;
}
}
Można to uruchomić na Ideone.com.
Java nie ma wskaźników takich jak C, ale umożliwia tworzenie nowych obiektów na stercie, do których „odwołują się” zmienne. Brak wskaźników ma uniemożliwić programom Java nielegalne odwoływanie się do lokalizacji pamięci, a także umożliwia automatyczne wykonywanie Garbage Collection przez wirtualną maszynę Java.
Możesz używać adresów i wskaźników za pomocą klasy Unsafe. Jednak, jak sama nazwa wskazuje, metody te są NIEBEZPIECZNE i ogólnie zły pomysł. Nieprawidłowe użycie może spowodować, że Twoja JVM przypadkowo umiera (w rzeczywistości ten sam problem pojawia się przy nieprawidłowym użyciu wskaźników w C / C ++)
Chociaż możesz być przyzwyczajony do wskaźników i myślisz, że ich potrzebujesz (ponieważ nie wiesz, jak kodować w inny sposób), przekonasz się, że tego nie robisz i będziesz na tym lepiej.
Technicznie rzecz biorąc, wszystkie obiekty Java są wskaźnikami. Jednak wszystkie typy pierwotne są wartościami. Nie ma możliwości ręcznego przejęcia kontroli nad tymi wskaźnikami. Java tylko wewnętrznie używa przekazywania przez odwołanie.
Nie, naprawdę nie.
Java nie ma wskaźników. Gdybyś naprawdę chciał, możesz spróbować je naśladować, budując wokół czegoś takiego jak odbicie, ale miałoby to całą złożoność wskaźników bez żadnych korzyści .
Java nie ma wskaźników, ponieważ ich nie potrzebuje. Jakich odpowiedzi oczekiwałeś w tym pytaniu, tj. Czy w głębi duszy miałeś nadzieję, że możesz ich użyć do czegoś, czy była to tylko ciekawość?
Wszystkie obiekty w Javie są przekazywane do funkcji przez kopię odniesienia, z wyjątkiem elementów pierwotnych.
W efekcie oznacza to, że wysyłasz kopię wskaźnika do oryginalnego obiektu, a nie kopię samego obiektu.
Zostaw komentarz, jeśli chcesz, aby przykład to zrozumiał.
swap
funkcji w Javie, która zamieni dwa obiekty.
Jak powiedzieli inni, krótka odpowiedź brzmi „nie”.
Jasne, możesz napisać kod JNI, który bawi się wskaźnikami Java. W zależności od tego, co próbujesz osiągnąć, może to gdzieś cię zaprowadzi, a może nie.
Zawsze możesz symulować punkty, tworząc tablicę i pracując z indeksami w tablicy. Ponownie, w zależności od tego, co próbujesz osiągnąć, może to być przydatne lub nie.
z książki o nazwie Decompiling Android autorstwa Godfrey'a Nolana
Bezpieczeństwo mówi, że wskaźniki nie są używane w Javie, więc hakerzy nie mogą przedostać się z aplikacji do systemu operacyjnego. Brak wskaźników oznacza, że coś innego - w tym przypadku JVM - musi zająć się alokowaniem i zwalnianiem pamięci. Wycieki pamięci również powinny przejść do przeszłości, a przynajmniej tak mówi teoria. Niektóre aplikacje napisane w C i C ++ są znane z przecieków pamięci jak sito, ponieważ programiści nie zwracają uwagi na zwalnianie niechcianej pamięci w odpowiednim czasie - nie znaczy to, że ktokolwiek to czyta, byłby winny takiego grzechu. Wyrzucanie elementów bezużytecznych powinno również zwiększyć produktywność programistów, poświęcając mniej czasu na debugowanie problemów z pamięcią.
możesz mieć również wskaźniki do literałów. Musisz je wdrożyć samodzielnie. Dla ekspertów jest to dość proste;). Użyj tablicy int / object / long / byte i voila, masz podstawy do implementowania wskaźników. Teraz dowolna wartość int może być wskaźnikiem do tej tablicy int []. Możesz zwiększyć wskaźnik, możesz zmniejszyć wskaźnik, możesz pomnożyć wskaźnik. Rzeczywiście masz arytmetykę wskaźnika! Tylko w ten sposób można zaimplementować 1000 klas atrybutów int i mieć ogólną metodę, która ma zastosowanie do wszystkich atrybutów. Możesz także użyć tablicy byte [] zamiast int []
Chciałbym jednak, aby Java pozwalała na przekazywanie wartości dosłownych przez odniesienie. Coś w tym stylu
//(* telling you it is a pointer)
public void myMethod(int* intValue);
Wszystkie obiekty java są wskaźnikami, ponieważ zmienna, która przechowuje adres, nazywa się wskaźnikiem, a adres trzymania obiektu. Więc obiekt jest zmienną wskaźnikową.